home *** CD-ROM | disk | FTP | other *** search
/ EnigmA Amiga Run 1995 October / EnigmA AMIGA RUN 01 (1995)(G.R. Edizioni)(IT)[!][issue 1995-10][Aminet 7].iso / Aminet / util / shell / csh543mberndt.lha / src / comm1.c next >
C/C++ Source or Header  |  1995-04-19  |  61KB  |  2,667 lines

  1. /*
  2.  * COMM1.C
  3.  *
  4.  * Matthew Dillon, August 1986
  5.  *
  6.  * Version 2.07M by Steve Drew 10-Sep-87
  7.  * Version 4.01A by Carlo Borreo & Cesare Dieni 17-Feb-90
  8.  * Version 5.00L by Urban Mueller 17-Feb-91
  9.  * Version 5.20L by Andreas M. Kirchwitz (Fri, 13 Mar 1992)
  10.  *
  11.  */
  12.  
  13. #include "shell.h"
  14.  
  15. /* comm1.c */
  16. static void display_file(char *filestr);
  17. static int search_file( long mask, char *s, char *fullpath );
  18. static int rm_file    ( long mask, char *s, char *fullpath );
  19. static int quicksearch(char *name, int nocasedep, char *pattern);
  20. static void setsystemtime(struct DateStamp *ds);
  21. static int found( char *lstart, int lnum, int loffs, char *name, char left );
  22.  
  23. void lformat( char *s, char *d, FILEINFO *info );
  24.  
  25. extern int has_wild;
  26.  
  27. int
  28. do_sleep( void )
  29. {
  30.     int i;
  31.  
  32.     if (ac == 2) for (i=atoi(av[1]); i>0 && !CHECKBREAK(); i--) Delay(50);
  33.     return 0;
  34. }
  35.  
  36. #if 0
  37. /* AMK: if you change this, you must change do_chmod() also!! */
  38. int
  39. do_protect( void )
  40. {
  41.     static char flags[]="DEWRAPSH";
  42.     char *s, *p;
  43.     long setmask=0, clrmask=0xFF, mask;
  44.     int  i, mode=0, stat;
  45.     DPTR *dp;
  46.  
  47.     for (s=strupr(av[--ac]); *s; s++) {
  48.         if (*s=='=') { mode=0; continue; }
  49.         if (*s=='+') { mode=1; clrmask=FIBF_ARCHIVE; continue; }
  50.         if (*s=='-') { mode=2; clrmask=FIBF_ARCHIVE; continue; }
  51.  
  52.         if (*s=='X') *s='E';
  53.         if (p=index(flags, *s)) {
  54.             if( mode==0 ) setmask|= 1<<(p-flags), clrmask=0xFF;
  55.             if( mode==1 ) setmask|= 1<<(p-flags);
  56.             if( mode==2 ) clrmask|= 1<<(p-flags);
  57.         } else {
  58.             ierror(av[ac],500);
  59.             return 20;
  60.         }
  61.     }
  62.  
  63.     for (i=1; i<ac; i++) {
  64.         if( (dp=dopen(av[i],&stat))) {
  65.             mask = dp->fib->fib_Protection ^ 0x0F;
  66.             mask&=~clrmask;
  67.             mask|= setmask;
  68.             dclose(dp);
  69.             if( !SetProtection( av[i], mask ^ 0x0F))
  70.                 pError(av[i]);
  71.         } else
  72.             pError(av[i]);
  73.     }
  74.     return 0;
  75. }
  76. #endif
  77.  
  78. /* AMK: same as do_protect, but flags now as first argument */
  79. #if 0
  80. int
  81. do_chmod( void )
  82. {
  83.     static char flags[]="DEWRAPSH";
  84.     char *s, *p;
  85.     long setmask=0, clrmask=0xFF, mask;
  86.     int  i, mode=0, stat;
  87.     DPTR *dp;
  88.  
  89.     for (s=strupr(av[1]); *s; s++) {       /* AMK: changed */
  90.         if (*s=='=') { mode=0; continue; }
  91.         if (*s=='+') { mode=1; clrmask=FIBF_ARCHIVE; continue; }
  92.         if (*s=='-') { mode=2; clrmask=FIBF_ARCHIVE; continue; }
  93.  
  94.         if (*s=='X') *s='E';
  95.         if (p=index(flags, *s)) {
  96.             if( mode==0 ) setmask|= 1<<(p-flags), clrmask=0xFF;
  97.             if( mode==1 ) setmask|= 1<<(p-flags);
  98.             if( mode==2 ) clrmask|= 1<<(p-flags);
  99.         } else {
  100.             ierror(av[1],500);     /* AMK: changed */
  101.             return 20;
  102.         }
  103.     }
  104.  
  105.     for (i=2; i<ac; i++) {                 /* AMK: changed */
  106.         if( (dp=dopen(av[i],&stat))) {
  107.             mask = dp->fib->fib_Protection ^ 0x0F;
  108.             mask&=~clrmask;
  109.             mask|= setmask;
  110.             dclose(dp);
  111.             if( !SetProtection( av[i], mask ^ 0x0F))
  112.                 pError(av[i]);
  113.         } else
  114.             pError(av[i]);
  115.     }
  116.     return 0;
  117. }
  118. #endif
  119.  
  120. #define FIBB_HOLD 7
  121. #define FIBF_HOLD (1<<FIBB_HOLD)
  122.  
  123. int do_chmod_internal(long arg_begin,long arg_end,long arg_flags)
  124. {
  125.     char *s;
  126.     LONG mask;
  127.     int  i, stat;
  128.     DPTR *dp;
  129.     BOOL do_user=FALSE,do_group=FALSE,do_other=FALSE,do_default=TRUE;
  130.     BOOL do_incl=FALSE,do_excl=FALSE,do_set=TRUE;
  131.  
  132.     /*strlwr(av[1]);*/
  133.  
  134.     for (i=arg_begin; i<arg_end; i++) {  /* all arguments except 'arg_flags' */
  135.  
  136.         if( (dp=dopen(av[i],&stat))) {
  137.             mask = dp->fib->fib_Protection;
  138.             dclose(dp);
  139.  
  140.             s = av[arg_flags];
  141.  
  142.             if (strchr(s,'+') || strchr(s,'-') || strchr(s,'=')) {
  143.  
  144.                 while (*s && !strchr("+-=",*s)) {
  145.                     switch (*s) {
  146.                     case 'u': do_user  = TRUE; break;
  147.                     case 'g': do_group = TRUE; break;
  148.                     case 'o': do_other = TRUE; break;
  149.                     case 'a': do_user  =
  150.                               do_group = 
  151.                               do_other = TRUE; break;
  152.                     default : ierror(av[1],500); return 20;
  153.                     }
  154.                     do_default = FALSE;
  155.                     ++s;
  156.                 }
  157.  
  158.                 do_set = FALSE;
  159.  
  160.                 switch (*s) {
  161.                 case '+': do_incl = TRUE; break;
  162.                 case '-': do_excl = TRUE; break;
  163.                 case '=': do_set  = TRUE; break;
  164.                 default : ierror(av[1],500); return 20;
  165.                 }
  166.  
  167.                 ++s;
  168.  
  169.             }
  170.  
  171.             if (do_default) {
  172.                 do_user=TRUE;
  173.             }
  174.  
  175.             if (do_set) {
  176.                 do_incl = TRUE;
  177.                 mask = FIBF_READ|FIBF_WRITE|FIBF_EXECUTE|FIBF_DELETE;
  178.             }
  179.  
  180.             mask &= (~FIBF_ARCHIVE);
  181.  
  182.             while (*s) {
  183.                 switch (*s) {
  184.                 case 'r' :
  185.                            if (do_incl) {
  186.                              if (do_user)  mask &= (~FIBF_READ);
  187.                              if (do_group) mask |= FIBF_GRP_READ;
  188.                              if (do_other) mask |= FIBF_OTR_READ;
  189.                            }
  190.                            else {
  191.                              if (do_user)  mask |= FIBF_READ;
  192.                              if (do_group) mask &= (~FIBF_GRP_READ);
  193.                              if (do_other) mask &= (~FIBF_OTR_READ);
  194.                            }
  195.                            break;
  196.                 case 'w' :
  197.                            if (do_incl) {
  198.                              if (do_user)  mask &= (~FIBF_WRITE);
  199.                              if (do_group) mask |= FIBF_GRP_WRITE;
  200.                              if (do_other) mask |= FIBF_OTR_WRITE;
  201.                            }
  202.                            else {
  203.                              if (do_user)  mask |= FIBF_WRITE;
  204.                              if (do_group) mask &= (~FIBF_GRP_WRITE);
  205.                              if (do_other) mask &= (~FIBF_OTR_WRITE);
  206.                            }
  207.                            break;
  208.                 case 'e' :
  209.                 case 'x' :
  210.                            if (do_incl) {
  211.                              if (do_user)  mask &= (~FIBF_EXECUTE);
  212.                              if (do_group) mask |= FIBF_GRP_EXECUTE;
  213.                              if (do_other) mask |= FIBF_OTR_EXECUTE;
  214.                            }
  215.                            else {
  216.                              if (do_user)  mask |= FIBF_EXECUTE;
  217.                              if (do_group) mask &= (~FIBF_GRP_EXECUTE);
  218.                              if (do_other) mask &= (~FIBF_OTR_EXECUTE);
  219.                            }
  220.                            break;
  221.                 case 'd' :
  222.                            if (do_incl) {
  223.                              if (do_user)  mask &= (~FIBF_DELETE);
  224.                              if (do_group) mask |= FIBF_GRP_DELETE;
  225.                              if (do_other) mask |= FIBF_OTR_DELETE;
  226.                            }
  227.                            else {
  228.                              if (do_user)  mask |= FIBF_DELETE;
  229.                              if (do_group) mask &= (~FIBF_GRP_DELETE);
  230.                              if (do_other) mask &= (~FIBF_OTR_DELETE);
  231.                            }
  232.                            break;
  233.                 case 'a' :
  234.                            if (do_incl)
  235.                              mask |= FIBF_ARCHIVE;
  236.                            else
  237.                              mask &= (~FIBF_ARCHIVE);
  238.                            break;
  239.                 case 'p' :
  240.                            if (do_incl)
  241.                              mask |= FIBF_PURE;
  242.                            else
  243.                              mask &= (~FIBF_PURE);
  244.                            break;
  245.                 case 's' :
  246.                            if (do_incl)
  247.                              mask |= FIBF_SCRIPT;
  248.                            else
  249.                              mask &= (~FIBF_SCRIPT);
  250.                            break;
  251.                 case 'h' :
  252.                            if (do_incl)
  253.                              mask |= FIBF_HOLD;
  254.                            else
  255.                              mask &= (~FIBF_HOLD);
  256.                            break;
  257.                 default  :
  258.                            ierror(av[1],500);
  259.                            return 20;
  260.                 }
  261.                 ++s;
  262.             }
  263.                         if (muBase) {
  264.                 if( !muSetProtection( av[i], mask ))
  265.                     pError(av[i]);
  266.                 }
  267.                 else {
  268.                     if( !SetProtection( av[i], mask ))
  269.                         pError(av[i]);
  270.                 }
  271.         }
  272.         else
  273.             pError(av[i]);
  274.     }
  275.  
  276.     return 0;
  277. }
  278.  
  279. int do_protect(void)
  280. {
  281.     return do_chmod_internal(1,ac-1,ac-1);
  282. }
  283.  
  284. int do_chmod(void)
  285. {
  286.     return do_chmod_internal(2,ac,1);
  287. }
  288.  
  289.  
  290.  
  291. int do_chown(void)
  292. {
  293.     LONG mask;  /* 2x UWORD */
  294.     UWORD new_id;
  295.     int  i, stat;
  296.     DPTR *dp;
  297.  
  298.     new_id = myatoi(av[1],0,65535);
  299.     if (atoierr) {
  300.         fprintf(stderr,"UID/GID is a 16-bit wide UWORD (0-65535) !\n");
  301.         return 20;
  302.     }
  303.  
  304.     for (i=2; i<ac; i++) {  /* all arguments except first */
  305.  
  306.         if( (dp=dopen(av[i],&stat))) {
  307.             /*printf("%s, gid %d, uid %d\n",av[i],dp->fib->fib_OwnerGID,dp->fib->fib_OwnerUID);*/
  308.             mask = dp->fib->fib_OwnerGID + (new_id<<16);
  309.             dclose(dp);
  310.  
  311.             /*printf("  new mask: %ld\n",mask);*/
  312.             if (DOSBase->dl_lib.lib_Version<39) {
  313.                 if( !SetOwner37( av[i], mask ))
  314.                     pError(av[i]);
  315.             }
  316.             else {
  317.                 if( !SetOwner( av[i], mask ))
  318.                     pError(av[i]);
  319.             }
  320.         }
  321.         else
  322.             pError(av[i]);
  323.     }
  324.  
  325.     return 0;
  326. }
  327.  
  328.  
  329.  
  330. int do_chgrp(void)
  331. {
  332.     LONG mask;  /* 2x UWORD */
  333.     UWORD new_id;
  334.     int  i, stat;
  335.     DPTR *dp;
  336.  
  337.     new_id = myatoi(av[1],0,65535);
  338.     if (atoierr) {
  339.         fprintf(stderr,"UID/GID is a 16-bit wide UWORD (0-65535) !\n");
  340.         return 20;
  341.     }
  342.  
  343.     for (i=2; i<ac; i++) {  /* all arguments except first */
  344.  
  345.         if( (dp=dopen(av[i],&stat))) {
  346.             /*printf("%s, gid %d, uid %d\n",av[i],dp->fib->fib_OwnerGID,dp->fib->fib_OwnerUID);*/
  347.             mask = (dp->fib->fib_OwnerUID<<16) + new_id;
  348.             dclose(dp);
  349.  
  350.             /*printf("  new mask: %ld\n",mask);*/
  351.             if (DOSBase->dl_lib.lib_Version<39) {
  352.                 if( !SetOwner37( av[i], mask ))
  353.                     pError(av[i]);
  354.             }
  355.             else {
  356.                 if( !SetOwner( av[i], mask ))
  357.                     pError(av[i]);
  358.             }
  359.         }
  360.         else
  361.             pError(av[i]);
  362.     }
  363.  
  364.     return 0;
  365. }
  366.  
  367.  
  368.  
  369. int
  370. do_filenote( void )
  371. {
  372.     DPTR *dp;
  373.     char *note;
  374.     int i, stat;
  375.  
  376.     if( options&1 ) {
  377.         for( i=1; i<ac && !dobreak(); i++ )
  378.             if( dp=dopen( av[i], &stat )) {
  379.                 printf( "%-12s %s\n", av[i],dp->fib->fib_Comment );
  380.                 dclose( dp );
  381.             }
  382.     } else {
  383.         note=av[--ac];
  384.         for (i=1; i<ac; i++) if (!SetComment(av[i], note)) pError(av[i]);
  385.     }
  386.     return 0;
  387. }
  388.  
  389. int
  390. do_cat( void )
  391. {
  392.     FILE *fi;
  393.     int lctr, i, docr=0;
  394.     char buf[256], *l;
  395.  
  396.     prepscroll(0);
  397.     if (ac<=1) {
  398.         if (has_wild) { printf("No files matching\n"); return 20; }
  399.         lctr=0;
  400.         while (fgets(buf,256,stdin) && !dobreak()) {
  401.             if (options) printf("%4d ",++lctr);
  402.             quickscroll();
  403.             l=buf+strlen( buf )-1; docr=1;
  404.             if( l>=buf && *l=='\n' ) docr=0;
  405.             fputs(buf,stdout);
  406.         }
  407.     } else {
  408.         for (i=1; i<ac; i++)
  409.             if (fi = fopen (av[i], "r")) {
  410.                 lctr=0;
  411.                 while (fgets(buf,256,fi) && !dobreak()) {
  412.                     if (options&1) printf("%4d ",++lctr);
  413.                     quickscroll();
  414.                     l=buf+strlen( buf )-1; docr=1;
  415.                     if( l>=buf && *l=='\n' ) docr=0;
  416.                     fputs(buf,stdout); fflush(stdout);
  417.                 }
  418.                 fclose (fi);
  419.             } else
  420.                 pError(av[i]);
  421.     }
  422.     if ( docr && IsInteractive(Output()) )
  423.         putchar('\n');
  424.     return 0;
  425. }
  426.  
  427.  
  428.  
  429. char *add_simple_device(char *list,char *dev)
  430. {
  431.     char *new = NULL;
  432.  
  433.     if (list) {
  434.         if (new = malloc(strlen(dev)+strlen(list)+2)) {        /* null byte + \n */
  435.             strcpy(new,list);
  436.             strcat(new,dev);
  437.             strcat(new,"\n");
  438.             free(list);
  439.         }
  440.         else
  441.             new = list;
  442.     }
  443.     else {
  444.         if (new = malloc(strlen(dev)+2)) {            /* null byte + \n */
  445.             strcpy(new,dev);
  446.             strcat(new,"\n");
  447.         }
  448.     }
  449.  
  450.     return(new);
  451. }
  452.  
  453.  
  454.  
  455. void
  456. get_drives(char *buf)
  457. {
  458.     struct DosList *dl;
  459.     ULONG flags = LDF_DEVICES|LDF_READ;
  460.     char devname[256];
  461.     char **dev_list=NULL;
  462.     long i,dev_num=0;
  463.  
  464.     buf[0]=0;
  465.     if (dl=LockDosList(flags)) {
  466.         while (dl=NextDosEntry(dl,flags)) {
  467.             if (dl->dol_Task) {
  468.                 BtoCStr(devname,dl->dol_Name,254L);  /* 256 - '\0' + ':' */
  469.                 strcat(devname,":");
  470.                 add_array_list(&dev_list,&dev_num,devname);
  471.             }
  472.         }
  473.         UnLockDosList(flags);
  474.     }
  475.  
  476.     QuickSort(dev_list,dev_num);
  477.  
  478.     for(i=0; i<dev_num; i++) {
  479.         if (IsFileSystem(dev_list[i])) {
  480.             if (buf[0])
  481.                 strcat(buf,"\240");
  482.             strcat(buf,dev_list[i]);
  483.         }
  484.     }
  485.  
  486.     free_array_list(dev_list,dev_num);
  487. }
  488.  
  489. static char infobuf[100];
  490. static char namebuf[32];  /* AMK: old size was 12, too small for drive names */
  491.  
  492.  
  493. /* AMK: find last occurence of a character in a string */
  494. char *strlast(char *s,char c)
  495. {
  496.   char *p=NULL;
  497.   while(*s) {
  498.     if(*s==c)
  499.       p=s;
  500.     s++;
  501.   }
  502.   return(p);
  503. }
  504.  
  505.  
  506. char *
  507. drive_name( char *name )
  508. {
  509.     struct DosList *dl;
  510.     struct MsgPort *proc= (struct MsgPort *)DeviceProc( (void*)name );
  511.     ULONG flags = LDF_DEVICES|LDF_READ;
  512.     char devname[256];
  513.     char **dev_list=NULL;
  514.     long i,dev_num=0;
  515.  
  516.     /* AMK: we want no self-modifying code */
  517.     strncpy( namebuf, name, 31 );   /* AMK: 30 chars device name + ':' */
  518.     namebuf[31] = '\0';             /* AMK: null-terminated */
  519.     if (dl=LockDosList(flags)) {
  520.         while (dl=NextDosEntry(dl,flags)) {
  521.             if (dl->dol_Task) {
  522.                 BtoCStr(devname,dl->dol_Name,254L);  /* 256 - '\0' + ':' */
  523.                 strcat(devname,":");
  524.                 add_array_list(&dev_list,&dev_num,devname);
  525.             }
  526.         }
  527.         UnLockDosList(flags);
  528.     }
  529.  
  530.     QuickSort(dev_list,dev_num);
  531.  
  532.     for(i=0; i<dev_num; i++) {
  533.         if (IsFileSystem(dev_list[i])) {
  534.             if ((struct MsgPort *)DeviceProc(dev_list[i])==proc)
  535.                 strcpy(namebuf,dev_list[i]);
  536.         }
  537.     }
  538.  
  539.     free_array_list(dev_list,dev_num);
  540.  
  541.     return namebuf;
  542. }
  543.  
  544. int
  545. do_info( void )
  546. {
  547.     struct DosList *dl;
  548.     ULONG flags = LDF_DEVICES|LDF_READ;
  549.     char devname[256];
  550.     char **dev_list=NULL;
  551.     long i,dev_num=0;
  552.  
  553.     if (options&2)
  554.         puts("Unit     Size  Block  Type   Used   Free Full Errs  Status    Name");
  555.     else
  556.         puts("Unit     Size  Bytes  Used Blk/Byte-Free Full Errs  Status    Name");
  557.  
  558.     if( ac==1 ) {
  559.         if (dl=LockDosList(flags)) {
  560.             while (dl=NextDosEntry(dl,flags)) {
  561.                 if (dl->dol_Task) {
  562.                     BtoCStr(devname,dl->dol_Name,254L);  /* 256 - '\0' + ':' */
  563.                     strcat(devname,":");
  564.                     add_array_list(&dev_list,&dev_num,devname);
  565.                 }
  566.             }
  567.             UnLockDosList(flags);
  568.         }
  569.  
  570.         QuickSort(dev_list,dev_num);
  571.  
  572.         for(i=0; !dobreak() && i<dev_num; i++) {
  573.             if (IsFileSystem(dev_list[i])) {
  574.                 oneinfo(dev_list[i],0);
  575.             }
  576.         }
  577.  
  578.         free_array_list(dev_list,dev_num);
  579.     }
  580.     else {
  581.         for( i=1; i<ac; i++ )
  582.             oneinfo( drive_name( av[i] ), 0 );
  583.     }
  584.  
  585.     return 0;
  586. }
  587.  
  588.  
  589.  
  590. /* these defines are new in OS 3.x */
  591. #ifndef ID_FASTDIR_DOS_DISK
  592. #define ID_FASTDIR_DOS_DISK (0x444F5304L)
  593. #endif
  594. #ifndef ID_FASTDIR_FFS_DISK
  595. #define ID_FASTDIR_FFS_DISK (0x444F5305L)
  596. #endif
  597.  
  598.  
  599.  
  600. /* AMK: new mode==6 to suppress output if disk is not present */
  601. char *
  602. oneinfo( char *name, int mode )
  603. {
  604.     struct InfoData *info;
  605.     struct DevProc *devproc;
  606.     struct DeviceList *dl;
  607.     BPTR lock;
  608.     long size, free, freebl, blocks;
  609.     char buf[130], *state, *type;
  610.     char *fmt="%s\240%s\240%d\240%d\240%d\240%s\240%d%%\240%d\240%s\240%s";
  611.  
  612.     Myprocess->pr_WindowPtr = (APTR)(-1);
  613.  
  614.     if (!name) name="";
  615.  
  616.     if (mode<=1 || mode>=5)
  617.         strcpy(infobuf,"");
  618.     else
  619.         strcpy(infobuf,"0");
  620.  
  621.     info=(struct InfoData *)SAllocMem(sizeof(struct InfoData),MEMF_PUBLIC|MEMF_CLEAR);
  622.  
  623.     if (devproc=GetDeviceProc(name,NULL)) {
  624.         if (DoPkt(devproc->dvp_Port,ACTION_DISK_INFO,MKBADDR(info),NULL,NULL,NULL,NULL)==DOSTRUE) {
  625.             BOOL go_on = FALSE;
  626.             char *spclfmt;
  627. #if 0
  628.             if (!NameFromLock(lock, buf, 128L)) {
  629.                 fprintf(stderr,"csh.oneinfo: NameFromLock() failed\n");
  630.                 strcpy(buf,name);
  631.             }
  632.             if (p=strlast(buf,':')) *p = '\0';
  633.             /* AMK: we want the last occurence of ':', not the first;
  634.                     ':' and '/' are legal path name components !!
  635.                     (bug only in RAM: disk)
  636.             if (p=index(buf,':')) *p = '\0';
  637.             */
  638. #endif
  639.             switch (mode) {
  640.                 case 0:
  641.                     if (options&1)
  642.                         spclfmt = "";
  643.                     else
  644.                         spclfmt = "%-7s %s\n";
  645.                     break;
  646.                 case 1:
  647.                     spclfmt = "%s\240%s\n";
  648.                     break;
  649.                 case 2:
  650.                 case 3:
  651.                 case 4:
  652.                     spclfmt = "0";
  653.                     break;
  654.                 case 5:
  655.                     spclfmt = "";
  656.                     break;
  657.                 default:
  658.                     spclfmt = "";
  659.                     break;
  660.             }
  661.  
  662.             switch (info->id_DiskType) {
  663.                 case ID_UNREADABLE_DISK:
  664.                     sprintf(infobuf,spclfmt,name,"Unreadable disk");
  665.                     break;
  666.                 case ID_NOT_REALLY_DOS:
  667.                     sprintf(infobuf,spclfmt,name,"Not a DOS disk");
  668.                     break;
  669.                 case ID_KICKSTART_DISK:
  670.                     sprintf(infobuf,spclfmt,name,"Kickstart disk");
  671.                     break;
  672.                 case (0x42555359L):  /* 'BUSY' */
  673.                     sprintf(infobuf,spclfmt,name,"Disk is busy");
  674.                     break;
  675.                 case ID_NO_DISK_PRESENT:
  676.                     sprintf(infobuf,spclfmt,name,"No disk present");
  677.                     break;
  678.                 default:
  679.                     sprintf(infobuf,spclfmt,name,"Unknown disk type");
  680.                     go_on = TRUE;
  681.                     break;
  682.             }
  683.  
  684.             if (go_on && (lock=Lock(name,ACCESS_READ))) {
  685.                 UnLock(lock);
  686.                 /* note:  we call Lock() to be sure that the volume is readable */
  687.  
  688.                 switch(info->id_DiskType) {
  689.                     case ID_MSDOS_DISK:       type=" MSDOS"; break;
  690.                     case ID_DOS_DISK:         type="   OFS"; break;
  691.                     case ID_FFS_DISK:         type="   FFS"; break;
  692.                     case ID_INTER_DOS_DISK:   type="IN/OFS"; break;
  693.                     case ID_INTER_FFS_DISK:   type="  INTL"; break;
  694.                     case ID_FASTDIR_DOS_DISK: type="DC/OFS"; break;
  695.                     case ID_FASTDIR_FFS_DISK: type="  DCFS"; break;
  696.                     default:                  type="   n/a"; break;
  697.                 }
  698.  
  699.                 strcpy(buf,"n/a");
  700.                 if (dl = (struct DeviceList *)BADDR(info->id_VolumeNode))
  701.                     BtoCStr(buf,dl->dl_Name,100L);
  702.  
  703.                 switch(info->id_DiskState) {
  704.                     case ID_WRITE_PROTECTED: state="Read Only "; break;
  705.                     case ID_VALIDATED:       state="Read/Write"; break;
  706.                     case ID_VALIDATING:      state="Validating"; break;
  707.                     default:                 state="Unknown   "; break;
  708.                 }
  709.  
  710. #if 0
  711.                 size   = (info->id_NumBlocks + 2) * info->id_BytesPerBlock;
  712. #endif
  713.                 size   = info->id_NumBlocks * info->id_BytesPerBlock;
  714.                 freebl = info->id_NumBlocks - info->id_NumBlocksUsed;
  715.                 free   = freebl * info->id_BytesPerBlock;
  716.                 blocks = info->id_NumBlocks;
  717. #if 0
  718.                 printf("percents: %s... %ld, %ld, %ld, %ld, %ld\n",name,
  719.                     ((info->id_NumBlocksUsed+2) * 100)/blocks,
  720.                     (info->id_NumBlocksUsed * 100)/(blocks+2),
  721.                     (((info->id_NumBlocksUsed * 1000)/blocks)+5)/10,
  722.                     ((((info->id_NumBlocksUsed+2) * 1000)/blocks)+5)/10,
  723.                     (((info->id_NumBlocksUsed * 1000)/(blocks+2))+5)/10
  724.                 );
  725. #endif
  726.  
  727.                 if (mode==0 && options&2) {
  728.                     fmt="%-7s%6s%6d %6s %6s %6s %3d%%%4d  %10s %s\n";
  729.                     sprintf(infobuf,fmt,
  730.                         name,
  731.                         itok( size ),
  732.                         info->id_BytesPerBlock,
  733.                         type,
  734.                         itok( info->id_NumBlocksUsed*info->id_BytesPerBlock ),
  735.                         itok( free ),
  736.                         (blocks) ? (int)((( (double)info->id_NumBlocksUsed/(double)blocks ) * 1000.0 + 5.0) / 10.0) : 0,
  737. #if 0
  738.                         (blocks) ? ((info->id_NumBlocksUsed * 1000)/blocks + 5) / 10 : 0,
  739. #endif
  740.                         info->id_NumSoftErrors,
  741.                         state,
  742.                         buf);
  743.                 }
  744.                 else if (mode<=1) {
  745.                     if (mode==0) fmt="%-7s%6s%6d%7d%7d %6s%4d%%%4d  %s %s\n";
  746.                     sprintf(infobuf,fmt,
  747.                         name,
  748.                         itok( size ),
  749.                         info->id_BytesPerBlock,
  750.                         info->id_NumBlocksUsed,
  751.                         freebl,
  752.                         itok( free ),
  753.                         (blocks) ? (int)((( (double)info->id_NumBlocksUsed/(double)blocks ) * 1000.0 + 5.0) / 10.0) : 0,
  754.                         info->id_NumSoftErrors,
  755.                         state,
  756.                         buf);
  757.                 }
  758.                 else if (mode==2) sprintf(infobuf,"%d",free);
  759.                 else if (mode==3) sprintf(infobuf,"%d",freebl);
  760.                 else if (mode==4) sprintf(infobuf,"%s",itok(free));
  761.                 else if (mode==5) sprintf(infobuf,"%s:",buf);
  762.             }
  763.         }
  764.         else
  765.             pError(name);
  766.         FreeDeviceProc(devproc);
  767.     }
  768.  
  769. #if 0
  770.     else {
  771.         if (mode==1) {
  772.             struct MsgPort *devtask;
  773.             sprintf(infobuf,"%s\240No disk present\n",name);
  774.             if (devtask=(struct MsgPort *)DeviceProc(name)) {
  775.                 struct InfoData *infodata;
  776.                 infodata = SAllocMem(sizeof(struct InfoData),MEMF_PUBLIC|MEMF_CLEAR);
  777.                 if (DoPkt(devtask,ACTION_DISK_INFO,MKBADDR(infodata),NULL,NULL,NULL,NULL)) {
  778.                     switch (infodata->id_DiskType) {
  779.                     case ID_UNREADABLE_DISK:
  780.                         sprintf(infobuf,"%s\240Unreadable disk\n",name);
  781.                         break;
  782.                     case ID_NOT_REALLY_DOS:
  783.                         sprintf(infobuf,"%s\240Not a DOS disk\n",name);
  784.                         break;
  785.                     case ID_KICKSTART_DISK:
  786.                         sprintf(infobuf,"%s\240Kickstart disk\n",name);
  787.                         break;
  788.                     case (0x42555359L):  /* 'BUSY' */
  789.                         sprintf(infobuf,"%s\240Busy\n",name);
  790.                         break;
  791.                     case ID_NO_DISK_PRESENT:
  792.                     default:
  793.                         sprintf(infobuf,"%s\240No disk present\n",name);
  794.                         break;
  795.                     }
  796.                 }
  797.                 FreeMem(infodata,sizeof(struct InfoData));
  798.             }
  799.         }
  800.         else if (mode==0) {
  801.             if (options&1) {
  802.                 sprintf(infobuf,"");
  803.             }
  804.             else {
  805.                 struct MsgPort *devtask;
  806.                 sprintf(infobuf,"%-7s No disk present\n",name);
  807.                 if (devtask=(struct MsgPort *)DeviceProc(name)) {
  808.                     struct InfoData *infodata;
  809.                     infodata = SAllocMem(sizeof(struct InfoData),MEMF_PUBLIC|MEMF_CLEAR);
  810.                     if (DoPkt(devtask,ACTION_DISK_INFO,MKBADDR(infodata),NULL,NULL,NULL,NULL)) {
  811.                         switch (infodata->id_DiskType) {
  812.                         case ID_UNREADABLE_DISK:
  813.                             sprintf(infobuf,"%-7s Unreadable disk\n",name);
  814.                             break;
  815.                         case ID_NOT_REALLY_DOS:
  816.                             sprintf(infobuf,"%-7s Not a DOS disk\n",name);
  817.                             break;
  818.                         case ID_KICKSTART_DISK:
  819.                             sprintf(infobuf,"%-7s Kickstart disk\n",name);
  820.                             break;
  821.                         case (0x42555359L):  /* 'BUSY' */
  822.                             sprintf(infobuf,"%-7s Disk is busy\n",name);
  823.                             break;
  824.                             case ID_NO_DISK_PRESENT:
  825.                         default:
  826.                             sprintf(infobuf,"%-7s No disk present\n",name);
  827.                             break;
  828.                         }
  829.                     }
  830.                     FreeMem(infodata,sizeof(struct InfoData));
  831.                 }
  832.             }
  833.         }
  834.         else if (mode==5) sprintf(infobuf,"");
  835.         else              sprintf(infobuf,"0");
  836.     }
  837. #endif
  838.  
  839.     if (mode==0) printf("%s",infobuf);
  840.  
  841.     FreeMem(info,sizeof(struct InfoData));
  842.     Myprocess->pr_WindowPtr = o_noreq ? (APTR) -1L : 0L/*Mywindow*/;
  843.  
  844.     return infobuf;
  845. }
  846.  
  847.  
  848. /* things shared with display_file */
  849.  
  850. #define DIR_SHORT 0x1
  851. #define DIR_FILES 0x2
  852. #define DIR_DIRS  0x4
  853. #define DIR_NOCOL 0x8
  854. #define DIR_NAMES 0x10
  855. #define DIR_HIDE  0x20
  856. #define DIR_LEN   0x40
  857. #define DIR_TIME  0x80
  858. #define DIR_BACK  0x100
  859. #define DIR_UNIQ  0x200
  860. #define DIR_IDENT 0x400
  861. #define DIR_CLASS 0x800
  862. #define DIR_QUIET 0x1000
  863. #define DIR_AGE   0x2000
  864. #define DIR_VIEW  0x4000
  865. #define DIR_NOTE  0x8000
  866. #define DIR_PATH  0x10000
  867. #define DIR_LFORM 0x20000
  868. #define DIR_BOT   0x40000
  869. #define DIR_TOP   0x80000
  870. #define DIR_LINK  0x100000
  871.  
  872. static char *lastpath = NULL;
  873. static int filecount, dircount, col, colw, wwidth;
  874. static long bytes, blocks;
  875.  
  876. /* the args passed to do_dir will never be expanded */
  877.  
  878. extern expand_err;
  879. extern int w_width;
  880.  
  881. static struct DateStamp Stamp;
  882. static char *LineBuf, *LinePos, LastWasDir, *LFormat, _LFormat[80], NoTitles;
  883.  
  884. int
  885. do_dir( void )
  886. {
  887.     int i=1, c, eac, reverse, nump=ac, retcode=0;
  888.     char **eav=NULL, **av1=NULL, **av2=NULL, inter=IsInteractive(Output());
  889.     char linebuf[1024];
  890.     char *fmtstr;
  891.     int (*func)(), ac1, ac2, factor=0;
  892.  
  893.     LineBuf=LinePos=linebuf;
  894.     LastWasDir=NoTitles=0;
  895.     colw = -1;
  896.  
  897.     LFormat=_LFormat;
  898.  
  899.     if( options&DIR_CLASS ) options|=DIR_IDENT;
  900.     if( !(options & (DIR_FILES | DIR_DIRS))) options|= DIR_FILES | DIR_DIRS;
  901.  
  902.     DateStamp( &Stamp );
  903.  
  904.     col = filecount = dircount = bytes = blocks = 0L;
  905.     if (lastpath) free(lastpath);
  906.     lastpath=NULL;
  907.  
  908.     wwidth=77;
  909.     if( inter )
  910.         wwidth=w_width;
  911.  
  912.     if( options&DIR_SHORT )
  913.         strcpy(LFormat," %-18n%19m");
  914.     else if( options&DIR_PATH )
  915.         strcpy(LFormat," %-50p %7s %d"), NoTitles=1;
  916.     else {
  917.         if ( options&DIR_NOTE )
  918.             strcpy(LFormat,"  %-30n %o");
  919.         else if ( options&DIR_LINK )
  920.             strcpy(LFormat,"  %-30n %L");
  921.         else {
  922. #if 1
  923.             strcpy(LFormat,"  ");
  924. #else
  925.             strcpy(LFormat,"  %-30n ");
  926. #endif
  927.             if( options&DIR_HIDE )
  928.                 strcat(LFormat, "%e");
  929.             strcat(LFormat,"%c%I%f ");
  930.             if( options&DIR_VIEW )
  931.                 strcat(LFormat,"%10v  ");
  932.             else
  933.                 strcat(LFormat,"%8s  ");
  934. #if 0
  935.             if( !(options&DIR_QUIET) )
  936.                 strcat(LFormat,options&DIR_VIEW?"%5b ":"%4b ");
  937. #endif
  938.             if( options&DIR_IDENT )
  939.                 strcat(LFormat,"%-10k");
  940.             else if( options&DIR_AGE )
  941.                 strcat(LFormat,"%a");
  942.             else
  943.                 strcat(LFormat,"%d %t");
  944. #if 1
  945.             strcat(LFormat,"  %N");
  946. #endif
  947.         }
  948.     }
  949.  
  950. #if 1
  951.     /* if option -z, use variable _dirformat or first argument (if no _dirformat) */
  952.  
  953.     if ( options&DIR_LFORM ) {
  954.         if ( fmtstr=get_var(LEVEL_SET,v_dirformat) ) {
  955.             strncpy(LFormat,fmtstr,79);    /* copy to _LFormat[80] */
  956.             LFormat[79]=0;
  957.         }
  958.         else if (ac>1)
  959.             LFormat=av[i++];
  960.         else {
  961.             show_usage(NULL);
  962.             return 20;
  963.         }
  964.     }
  965. #else
  966.     /* variable _dirformat always used, can be overwritten by -z fmt */
  967.  
  968.     if ( fmtstr=get_var(LEVEL_SET,v_dirformat) ) {
  969.         strncpy(LFormat,fmtstr,79);    /* copy to _LFormat[80] */
  970.         LFormat[79]=0;
  971.     }
  972.  
  973.     if ( options&DIR_LFORM ) {
  974.         if (ac>1)
  975.             LFormat=av[i++];
  976.         else {
  977.             show_usage(NULL);
  978.             return 20;
  979.         }
  980.     }
  981. #endif
  982.  
  983.     if( ac == i) ++nump, av[i]="";
  984.     if( options&DIR_UNIQ) {
  985.         if( ac-i!=2 )  { show_usage(NULL); return 20; }
  986.         i=0, nump=3;
  987.     }
  988.  
  989.     prepscroll(0);
  990.     for( ; i<nump && !CHECKBREAK(); ++i ) {
  991.         if( options&DIR_UNIQ ) {
  992.             switch( i ) {
  993.                 case 0: av1=expand( av[ac-2], &ac1 );
  994.                         av2=expand( av[ac-1], &ac2 );
  995.                         eav=without( av1, ac1, av2, ac2, &eac, 1 );
  996.                         break;
  997.                 case 1: printf("\nCommon files\n");
  998.                         eav=and( av1, ac1, av2, ac2, &eac, 1 );
  999.                         break;
  1000.                 case 2: printf("\n");
  1001.                         eav=without( av2, ac2, av1, ac1, &eac, 1 );
  1002.                         break;
  1003.             }
  1004.             col = filecount = dircount = bytes = blocks = 0L;
  1005.             if (lastpath) free(lastpath);
  1006.             lastpath=NULL;
  1007.  
  1008.         /* AMK: enhanced handling of non-matching patterns */
  1009.         } else if (!(eav = expand(av[i], &eac))) {
  1010.             if (IoError) {
  1011.                 ierror(av[i],IoError);
  1012.                 retcode=5;
  1013.             }
  1014. #if 0
  1015.             else {
  1016.                 if (strlen(av[i])>0)
  1017.                     fprintf(stderr,"%s: No match.\n",av[i]);
  1018.             }
  1019. #endif
  1020.             continue;
  1021.         }
  1022.  
  1023.         reverse= ( options&DIR_BACK ) ? 1 : 0;
  1024.         func=cmp;
  1025.         if( options & DIR_TIME) func   = datecmp_csh;
  1026.         if( options & DIR_LEN ) func   = sizecmp;
  1027.         if( options & DIR_CLASS)func   = classcmp;
  1028.         if( options & DIR_BOT ) factor = -99999999;
  1029.         if( options & DIR_TOP ) factor = 99999999;
  1030.         DirQuickSort(eav, eac, func, reverse, factor);
  1031.         for(c=0; c<eac && !CHECKBREAK(); ++c) {
  1032.             if( options & DIR_HIDE ) {
  1033.                 char *b=FilePart(eav[c]);
  1034.                 int  l=strlen(b)-5;
  1035.                 FILEINFO *info =(FILEINFO *)eav[c] - 1;
  1036.                 if(*b=='.'|| (l>=0 && !strcmp(b+l,".info"))||(info->flags&128))
  1037.                     continue;
  1038.             }
  1039.             if (options & DIR_NAMES) {
  1040.                 FILEINFO *info = (FILEINFO *)eav[c] - 1;
  1041.                 if(options&(info->size<0 ? DIR_DIRS: DIR_FILES))
  1042.                     puts(eav[c]);
  1043.             } else
  1044.                 display_file(eav[c]);
  1045.         }
  1046.  
  1047.         if (col) { quickscroll(); puts(LinePos=LineBuf); col=0; }
  1048.  
  1049.         if( LastWasDir )
  1050.             printf(o_lolite), LastWasDir=0;
  1051.  
  1052.         if (options&DIR_UNIQ || (filecount>1 && i==nump-1)) {
  1053.             blocks += filecount-dircount; /* account for dir blocks */
  1054.             quickscroll();
  1055.             printf(" %ld Blocks, %s Bytes used in %d files\n",
  1056.                 blocks, itoa(bytes), filecount);
  1057.         }
  1058.         if( options&DIR_UNIQ )
  1059.             free(eav);
  1060.         else
  1061.             free_expand (eav);
  1062.     }
  1063.     if (lastpath) free(lastpath);
  1064.     lastpath=NULL;
  1065.  
  1066.     if( options&DIR_UNIQ )
  1067.         free_expand( av1 ), free_expand( av2 );
  1068.  
  1069.     return retcode;
  1070. }
  1071.  
  1072. static int MultiCol = -1;
  1073.  
  1074. static char
  1075. pathcomp( char *s1, char *s2 )
  1076. {
  1077.     char ret, *t, c;
  1078.  
  1079.     t=FilePart( s2 ); c = *t; *t=0;
  1080.     ret=stricmp( s1, s2 );
  1081.     *t=c;
  1082.     return ret;
  1083. }
  1084.  
  1085. static void
  1086. display_file( char *filestr )
  1087. {
  1088.     /* struct InfoData *id=AllocMem( sizeof(struct InfoData), 0); */
  1089.     int isadir, len, collen;
  1090.     char sc, *base, buf[1024], *hilite;
  1091.     FILEINFO *info;
  1092.     BPTR thislock;
  1093.  
  1094.     base=FilePart(filestr);
  1095.     sc = *base;
  1096.     *base = 0;
  1097.     /* if (thislock==NULL) return; */
  1098.     if( !NoTitles ) {
  1099.         if( !lastpath || pathcomp( filestr, lastpath)) {
  1100.             if(!(thislock=Lock(filestr,SHARED_LOCK)))
  1101.                 return;
  1102.             if (col) { quickscroll(); puts(LinePos=LineBuf); col=0; }
  1103.             quickscroll();
  1104.             if (!NameFromLock(thislock, buf, 256)) {
  1105.                 fprintf(stderr,"csh.display_file: NameFromLock() failed\n");
  1106.                 strcpy(buf,filestr);
  1107.             }
  1108.             if( LastWasDir )
  1109.                 printf(o_lolite), LastWasDir=0;
  1110.             printf("Directory of %s\n", buf );
  1111.             /* Info( thislock, id ); */
  1112.             /* itok((id->id_NumBlocks-id->id_NumBlocksUsed)*id->id_BytesPerBlock));*/
  1113.             /* FreeMem( id, sizeof(struct InfoData)); */
  1114.             lastpath = salloc(256);
  1115.             strcpy(lastpath,filestr);
  1116.             /*lastpath=filestr;*/
  1117.             UnLock(thislock);
  1118.         }
  1119.     }
  1120.     *base    = sc;
  1121.  
  1122.     info   = (FILEINFO *)filestr - 1;
  1123.     isadir = info->size<0;
  1124.  
  1125.     if( !(options & (isadir ? DIR_DIRS : DIR_FILES)))
  1126.         return;
  1127.  
  1128.     hilite="";
  1129.     if (isadir!=LastWasDir && !(options & DIR_NOCOL))
  1130.         hilite=isadir ? o_hilite : o_lolite, LastWasDir=isadir;
  1131.  
  1132.     lformat(LFormat, buf, info);
  1133.  
  1134.     if( MultiCol == -1 ) {
  1135.         quickscroll();
  1136.         printf("%s%s",hilite,buf);
  1137.     } else {
  1138.         len=strlen(buf);
  1139.         if( col+len>wwidth ) {
  1140.             quickscroll();
  1141.             puts(LineBuf);
  1142.             LinePos=LineBuf; col=0;
  1143.         }
  1144.         if( MultiCol )
  1145.             colw=MultiCol;
  1146.         else if( colw == -1 )
  1147.             colw=len;
  1148.         collen= (len+colw-1)-(len+colw-1)%colw;
  1149.         col+=collen;
  1150.         LinePos+=sprintf(LinePos,"%s%-*s",hilite,collen,buf);
  1151.     }
  1152.  
  1153.     if(info->size>0)
  1154.         bytes  += info->size;
  1155.     blocks += info->blocks;
  1156.     filecount++;
  1157. }
  1158.  
  1159. static char linebuf[1024];
  1160. static long dlen, dblocks;
  1161.  
  1162. static int
  1163. count( long mask, char *s, char *path )
  1164. {
  1165.     FIB *fib=(FIB*)s-1;
  1166.     dlen+=fib->fib_Size;
  1167.     dblocks+=fib->fib_NumBlocks+1;
  1168.     return 0;
  1169. }
  1170.  
  1171.  
  1172. /* code contribution by Carsten Heyl, modified by AMK */
  1173. void ReadSoftLink(char *path, char *buf, int buflen)
  1174. {
  1175.     BPTR MyLock;
  1176.     BPTR DevLock;
  1177.     LONG Err, l;
  1178.     UBYTE *bs;
  1179.     struct MsgPort *port;
  1180.  
  1181.     if (buflen>9)
  1182.         strcpy(buf,"<unknown>");
  1183.     else
  1184.         buf[0] = '\0';    /* just terminate buffer. alternative ? */
  1185.  
  1186.     if ( (l=strlen(path)) > 254 )
  1187.         return;
  1188.  
  1189.     if (!(bs=AllocMem(256,MEMF_CLEAR|MEMF_PUBLIC)))
  1190.         return;
  1191.  
  1192.     bs[255] = '\0';
  1193.  
  1194.     /* build BCPL string */
  1195.     bs[0] = l;
  1196.     memcpy(&bs[1], path, l+1);
  1197.  
  1198.     /* GetDeviceProc or DeviceProc? */
  1199.     if (!(port = DeviceProc(path))) {
  1200.         FreeMem(bs,256);
  1201.         return;
  1202.     }
  1203.  
  1204.     DevLock = (BPTR)IoErr();
  1205.  
  1206.     MyLock = DoPkt(port,ACTION_LOCATE_OBJECT,DevLock,MKBADDR(bs),
  1207.                 ACCESS_READ,NULL,NULL);
  1208.     Err = IoErr();
  1209.  
  1210.     if (!MyLock && (Err==ERROR_IS_SOFT_LINK)) {
  1211. #if 0
  1212.         ReadLink(port,DevLock,(UBYTE *)path,(UBYTE *)buf,buflen);
  1213. #else
  1214.         DoPkt(port,ACTION_READ_LINK,DevLock,(LONG)path,(LONG)buf,buflen,NULL);
  1215. #endif
  1216.     }
  1217.  
  1218.     if (MyLock) UnLock(MyLock);
  1219.     FreeMem(bs,256);
  1220. }
  1221.  
  1222.  
  1223. void
  1224. lformat( char *s, char *d, FILEINFO *info )
  1225. {
  1226.     long mi=0;
  1227.     char buf[1024], *w, *t, *class;
  1228.     DPTR *dp;
  1229.     int stat, i, form, sign, cut, size=info->size;
  1230.     char *(*func)(int num);
  1231.  
  1232.     MultiCol = -1;
  1233.     while( *s ) {
  1234.         if( *s!='%' ) { *d++ = *s++; continue; }
  1235.         sign=1; form=0; cut=0; s++;
  1236.         if( *s=='-' ) s++, sign = -1;
  1237.         if( *s=='.' ) s++, cut=1;
  1238.         while( *s>='0' && *s<='9' ) form=10*form+*s++-'0';
  1239.         w=buf; w[0]=0; w[1]=0;
  1240.         switch( *s ) {
  1241.         case 'p': strcpy(w,(char *)(info+1));             break;
  1242.         case 'b': sprintf(w,size>=0 ? "%d":"", info->blocks); break;
  1243.         case 's': sprintf(w,size>=0 ? "%d":"<Dir>",size); break;
  1244.         case 'i': *w= size>=0 ? '-' : 'd';                break;
  1245.         case 'r':
  1246.         case 'u':
  1247.             if( *s=='r' ) func=itoa; else func=itok;
  1248.             strcpy( w,size>=0 ? (*func)(size) : "<Dir>");
  1249.             break;
  1250.         case 'n':
  1251.         case 'q':
  1252.             strcpy(w,FilePart((char *)(info+1)));
  1253.             if( *s=='q' && size<0 ) strcat(w,"/");
  1254.             break;
  1255.         case 'l':
  1256.             if( info->flags & INFO_COMMENT ) *w='\n';
  1257.             break;
  1258.         case 'c':
  1259.             *w= info->flags & INFO_COMMENT ? 'c' : '-';
  1260.             break;
  1261.         case 'e':
  1262.             *w= info->flags & INFO_INFO ? 'i' : '-';
  1263.             break;
  1264.         case '+':
  1265.             *w= info->flags & INFO_INFO ? '+' : ' ';
  1266.             break;
  1267.         case 'L':
  1268.         case 'N':
  1269.             if (*s=='N')
  1270.                 strcpy(w,FilePart((char *)(info+1)));
  1271.             else
  1272.                 strcpy(w,"");
  1273.             if (info->type==ST_SOFTLINK) {
  1274.                 strcat(w," -> ");
  1275.                 ReadSoftLink((char *)(info+1),w+strlen(w),256);
  1276.             }
  1277.             else if (info->type==ST_LINKDIR || info->type==ST_LINKFILE) {
  1278.                 BPTR lock;
  1279.                 if (lock=Lock((char *)(info+1),ACCESS_READ)) {
  1280.                     strcat(w," -> ");
  1281.                     if (!NameFromLock(lock,w+strlen(w),256)) {
  1282.                         fprintf(stderr,"csh.lformat: NameFromLock() failed\n");
  1283.                         strcpy(w+strlen(w),(char *)(info+1));
  1284.                     }
  1285.                     UnLock(lock);
  1286.                 }
  1287.             }
  1288.             break;
  1289.         case 'I':
  1290.             switch (info->type) {
  1291.                 case ST_SOFTLINK:
  1292.                     *w='S';
  1293.                     break;
  1294.                 case ST_LINKDIR:
  1295.                 case ST_LINKFILE:
  1296.                     *w='H';
  1297.                     break;
  1298.                 case ST_PIPEFILE:
  1299.                     *w='P';
  1300.                     break;
  1301.                 default:
  1302.                     *w='-';
  1303.                     break;
  1304.             }
  1305.             break;
  1306.         case 'f': /* standard flags */
  1307.             for (i=7; i>=0; i--)
  1308.                 *w++ = (info->flags^15) & (1L<<i) ? "hsparwed"[7-i] : '-';
  1309.             *w=0;
  1310.             break;
  1311.         case 'F': /* group/other flags */
  1312.             for (i=3; i>=0; i--)
  1313.                 *w++ = (info->flags^15) & (1L<<(i+8)) ? "rwed"[3-i] : '-';
  1314.             *w++ = ' ';
  1315.             for (i=3; i>=0; i--)
  1316.                 *w++ = (info->flags^15) & (1L<<(i+12)) ? "rwed"[3-i] : '-';
  1317.             *w=0;
  1318.             break;
  1319.         case 'U': /* user-id */
  1320.             sprintf(w,"%d",info->uid);
  1321.             break;
  1322.         case 'G': /* group-id */
  1323.             sprintf(w,"%d",info->gid);
  1324.             break;
  1325.         case 'a':
  1326.             if( Stamp.ds_Days!=0 ) {
  1327.                 mi =Stamp.ds_Days*1440 + Stamp.ds_Minute;
  1328.                 mi-=info->date.ds_Days*1440 + info->date.ds_Minute;
  1329.             }
  1330.             sprintf(w,mi>=0?"%4d days %02d:%02d":"Future    ",
  1331.                       mi/1440,mi/60%60,mi%60);
  1332.             break;
  1333.         case 'o':
  1334.             if( dp=dopen( (char *)(info+1), &stat )) {
  1335.                 strcpy( w, dp->fib->fib_Comment );
  1336.                 dclose( dp );
  1337.             }
  1338.             break;
  1339.         case 'v':
  1340.         case 'w':
  1341.             if( *s=='v' ) func=itoa; else func=itok;
  1342.             dlen=dblocks=0;
  1343.             if( size<0 ) {
  1344.                 newrecurse( SCAN_DIR|SCAN_FILE|SCAN_RECURSE,
  1345.                             (char *)(info+1),count);
  1346.                 strcpy( w, (*func)(dlen));
  1347.                 info->size=size=dlen; info->blocks=dblocks;
  1348.             } else
  1349.                 strcpy( w, (*func)(size));
  1350.             break;
  1351.         case 'k':
  1352.             if( *info->class!=1 )
  1353.                 strcpy(w,info->class);
  1354.             else if( class=getclass((char *)(info+1)))
  1355.                 if( w=index(strncpy(w,class,50),0xA0) )
  1356.                     *w=0;
  1357.             break;
  1358.         case 'x':
  1359.         case 'd':
  1360.             sprintf(w,"%9s",dates(&info->date,*s=='x'));
  1361.             if(t=index(w,' ')) *t=0;
  1362.             break;
  1363.         case 't':
  1364.             sprintf(w,"%8s", next_word(dates(&info->date,0)));
  1365.             break;
  1366.         case 'm': MultiCol = form; form = 0;    break;
  1367.         case '%': *w = *++s;                    break;
  1368.         case  0 : *w = '%';                     break;
  1369.         default : *w = '%';  *w++ = *s; *w = 0; break;
  1370.         }
  1371.         if( cut ) buf[form]=0;
  1372.         *d=0; s++;
  1373.         d+=sprintf(d,sign<0?"%-*s":"%*s",form,buf);
  1374.     }
  1375.     if( MultiCol == -1 ) { *d++='\n'; }
  1376.     *d=0;
  1377. }
  1378.  
  1379.  
  1380.  
  1381. extern BOOL nologout;    /* defined in main.c */
  1382.  
  1383. int
  1384. do_quit( void )
  1385. {
  1386.     if (Src_stack) {
  1387.         Quit = 1;
  1388.         return(do_return());
  1389.     }
  1390.     if (!nologout) {
  1391.         if( exists("S:.logout"))
  1392.             execute("source S:.logout");
  1393.     }
  1394.     main_exit(0);
  1395.     return 0;
  1396. }
  1397.  
  1398. int
  1399. do_echo( void )
  1400. {
  1401.     char *args=compile_av(av,1,ac,' ',0);
  1402.     fprintf( (options&2)?stderr:stdout, (options&1)?"%s":"%s\n",args );
  1403.     free(args);
  1404.     return 0;
  1405. }
  1406.  
  1407.  
  1408. static int
  1409. breakcheckd(void)
  1410. {
  1411.     long sigs = SetSignal(0L,0L);
  1412.     int ret=!o_nobreak && (sigs & SIGBREAKF_CTRL_D);
  1413.     if (ret)
  1414.         fprintf(stderr,"^D\n");
  1415.     return ret;
  1416. }
  1417.  
  1418. static int
  1419. breakchecke(void)
  1420. {
  1421.     long sigs = SetSignal(0L,0L);
  1422.     int ret=!o_nobreak && (sigs & SIGBREAKF_CTRL_E);
  1423.     if (ret)
  1424.         fprintf(stderr,"^E\n");
  1425.     return ret;
  1426. }
  1427.  
  1428.  
  1429. /* gets a line from file, joining lines if they end in '\' */
  1430.  
  1431. #define MAXLINE 512
  1432.  
  1433. static int
  1434. srcgets(char **buf, int *buflen, FILE *file)
  1435. {
  1436.     char *bufptr = *buf, *p, *new, concat=0, cont;
  1437.     int   totlen=0, len;
  1438.  
  1439.     do {
  1440.         if( totlen+MAXLINE > *buflen ) {
  1441.             new=salloc(*buflen *= 2);
  1442.             memcpy( new, *buf, 1+bufptr-*buf );
  1443.             bufptr+= new-*buf;
  1444.             free(*buf);
  1445.             *buf=new;
  1446.         }
  1447.         if (fgets(bufptr, MAXLINE, file)==NULL) {
  1448.             if( concat )
  1449.                 fprintf(stderr,"Source: missing '}'\n");
  1450.             else if (bufptr != *buf)
  1451.                 fprintf(stderr,"Source: file ends in '\\'\n");
  1452.             return -1;
  1453.         }
  1454.         len= strlen( bufptr );
  1455.         totlen+= len;
  1456.  
  1457.         cont=0;
  1458.  
  1459.         p=bufptr+len-1;
  1460.         if(  p>=bufptr && *p=='\n') *p--=0;
  1461.         if(  p< bufptr   ) ;
  1462.         else if( *p=='\\') *p--=0, cont=1;
  1463.         else if( *p=='{' ) concat++;
  1464.         else if( *p=='}' ) {
  1465.             if( concat>0 ) {
  1466.                 concat--;
  1467.                 if( concat ) *++p='\n';
  1468.             }
  1469.         } else if( concat ) *++p='\n';
  1470.         bufptr = ++p;
  1471.     } while( cont || concat );
  1472.     *bufptr=0;
  1473.     return totlen;
  1474. }
  1475.  
  1476.  
  1477.  
  1478. int
  1479. do_source( char *str )
  1480. {
  1481.     FILE *fi;
  1482.     char *buf;
  1483.     ROOT *root;
  1484.     int  retcode, len, bufsize=512+MAXLINE;
  1485.     int j;
  1486.     char *ptr;
  1487.  
  1488.     if (Src_stack == MAXSRC) {
  1489.         ierror(NULL,217);
  1490.         return -1;
  1491.     }
  1492.  
  1493.     if ((fi = fopen (av[1], "r")) == 0)
  1494.         { pError(av[1]); return -1;    }
  1495.  
  1496.     push_locals(root=(ROOT *)salloc( sizeof(ROOT)));
  1497.     buf=salloc(bufsize);
  1498.  
  1499.     set_var(LEVEL_SET | LEVEL_LOCAL, v_passed, next_word(next_word(str)));
  1500.  
  1501.  
  1502.     /*
  1503.      * now create a bunch of positional parameters , $0, $1 etc
  1504.      */
  1505.     j = 0;
  1506.     ptr = next_word (str);
  1507.     while (*ptr) {
  1508.         char *var;
  1509.         char p[6];
  1510.         char npos[6];
  1511.  
  1512.         var = ptr;
  1513.         sprintf (p, "%d", j);
  1514.         /*
  1515.          * term var str
  1516.          */
  1517.         ptr = next_word (ptr);
  1518.  
  1519.         /* printf("%s\n" , ptr); */
  1520.  
  1521.         if (*ptr)
  1522.             *(ptr - 1) = '\0';
  1523.  
  1524.         set_var (LEVEL_SET | LEVEL_LOCAL, p, var);
  1525.         /*
  1526.          * now set up what should be $# ( number of positionals )
  1527.          */
  1528. #if 0
  1529.         sprintf (p, "_N");    /* should be "#" but csh barfs :( */
  1530. #endif
  1531.         sprintf (p, "#");    /* hackin' */
  1532.         sprintf (npos, "%d", j++);
  1533.         set_var (LEVEL_SET | LEVEL_LOCAL, p, npos);
  1534.     }
  1535.  
  1536.  
  1537.     Src_pos  [Src_stack] = 0;
  1538.     Src_abort[Src_stack] = 0;
  1539.     Src_base [Src_stack] = fi;
  1540.     Src_if[Src_stack]=If_stack;
  1541.     ++Src_stack;
  1542.     while ((len=srcgets(&buf, &bufsize, fi))>=0&& !dobreak()&& !breakcheckd()){
  1543.         Src_pos[Src_stack-1] += len;
  1544.         if (Verbose&VERBOSE_SOURCE && !forward_goto)
  1545.             if( Verbose&VERBOSE_HILITE )
  1546.                 fprintf(stderr,"%s)%s%s\n",o_hilite,buf,o_lolite);
  1547.             else
  1548.                 fprintf(stderr,")%s\n",buf);
  1549.         retcode=execute(buf);
  1550.         if( retcode>=o_failat || Src_abort[Src_stack-1] )
  1551.             break;
  1552.         retcode=0;
  1553.     }
  1554.     --Src_stack;
  1555.     if( If_stack>Src_if[Src_stack] )
  1556.         If_stack=Src_if[Src_stack], disable=If_stack && If_base[If_stack-1];
  1557.  
  1558.     if (forward_goto) ierror(NULL,501);
  1559.     forward_goto = 0;
  1560.     unset_level(LEVEL_LABEL+ Src_stack);
  1561.     unset_var(LEVEL_SET, v_gotofwd);
  1562.     unset_var(LEVEL_SET, v_passed);
  1563.     fclose (fi);
  1564.  
  1565.     pop_locals();
  1566.     free(buf);
  1567.     free(root);
  1568.  
  1569.     return retcode;
  1570. }
  1571.  
  1572. /* set process cwd name and $_cwd, if str != NULL also print it. */
  1573.  
  1574. void
  1575. set_cwd(void)
  1576. {
  1577.     char pwd[256];
  1578.  
  1579.     if (!NameFromLock(Myprocess->pr_CurrentDir, pwd, 254)) {
  1580.         fprintf(stderr,"csh.set_cwd: NameFromLock() failed\n");
  1581.         strcpy(pwd,"<unknown>");
  1582.     }
  1583.     set_var(LEVEL_SET, v_cwd, pwd);
  1584.     /* put the current dir name in our CLI task structure */
  1585.     CtoBStr(pwd, Mycli->cli_SetName, 254);
  1586. }
  1587.  
  1588. int
  1589. do_pwd( void )
  1590. {
  1591.     set_cwd();
  1592.     puts( get_var( LEVEL_SET, v_cwd ));
  1593.     return 0;
  1594. }
  1595.  
  1596.  
  1597. /*
  1598.  * CD
  1599.  *
  1600.  * CD(str, 0)      -do CD operation.
  1601.  *
  1602.  */
  1603.  
  1604. extern int qcd_flag;
  1605.  
  1606. static char lastqcd[256];
  1607. static FILE *qcdfile;
  1608. static int  NumDirs;
  1609.  
  1610. static int
  1611. countfunc( long mask, char *file, char *fullpath )
  1612. {
  1613.     fprintf( qcdfile, "%s\n", fullpath );
  1614.     fprintf( stdout, "\r Directories: %d", ++NumDirs );
  1615.     fflush ( stdout );
  1616.     return 0;
  1617. }
  1618.  
  1619. int
  1620. do_cd(void)
  1621. {
  1622.     BPTR oldlock, filelock;
  1623.     char buf[256], *old, *str=av[1];
  1624.     int  i=1, repeat;
  1625.  
  1626.     if( options & 1 ) {
  1627.         if( !o_csh_qcd ) { fprintf(stderr,"$_qcd unset\n"); return 20; }
  1628.         if( !(qcdfile=fopen( o_csh_qcd, "w" )))
  1629.             { fprintf(stderr,"Can't open output\n"); return 20; }
  1630.         for( ; i<ac && !dobreak(); i++ ) {
  1631.             NumDirs=0;
  1632.             printf("%s\n",av[i]);
  1633.             newrecurse( SCAN_DIRENTRY | SCAN_RECURSE, av[i], countfunc );
  1634.             printf("\n");
  1635.         }
  1636.         fclose(qcdfile);
  1637.         return 0;
  1638.     }
  1639.  
  1640.     if ( !str || !(*str) ) {    /* old "!*str" causes enforcer hit! */
  1641.         printf("%s\n", get_var( LEVEL_SET, v_cwd ));
  1642.         return 0;
  1643.     }
  1644.  
  1645.     if (filelock=Lock(str,ACCESS_READ)) {
  1646.         lastqcd[0]=0;
  1647.         if (!isdir(str)) { UnLock(filelock); ierror(str,212); return 20; }
  1648.     } else {
  1649.         repeat= !strncmp( lastqcd, str, 255 );
  1650.         strncpy( lastqcd, str, 255 );
  1651.  
  1652.         if( !quick_cd( buf, av[i], repeat) )
  1653.             { fprintf(stderr,"Object not found %s\n",str); return 20; }
  1654.         if (!(filelock=Lock(buf,ACCESS_READ)))
  1655.             { pError(buf); return 20; }
  1656.     }
  1657.     if (oldlock=CurrentDir(filelock)) UnLock(oldlock);
  1658.     if( !(old=get_var(LEVEL_SET, v_cwd)) )
  1659.         old="";
  1660.     set_var(LEVEL_SET, v_lcd, old);
  1661.     set_cwd();
  1662.  
  1663.     return 0;
  1664. }
  1665.  
  1666. char *
  1667. quick_cd( char *buf, char *name, int repeat )
  1668. {
  1669.     if( !o_csh_qcd || !exists(o_csh_qcd))
  1670.         return NULL;
  1671.     qcd_flag=repeat ? 2 : 1;
  1672.     strcpy(buf,name);
  1673.     if( quicksearch( o_csh_qcd, 1, buf)!=2 )
  1674.         return NULL;
  1675.     return buf;
  1676. }
  1677.  
  1678.  
  1679. /* AMK: mkdir now builds path to destination directory if neccessary */
  1680. int
  1681. do_mkdir( void )
  1682. {
  1683.     int i;
  1684.     BPTR lock;
  1685.     char *p,c;
  1686.  
  1687.     for (i=1; i<ac; ++i) {
  1688.  
  1689.         /* Are there any sub-directories to build? */
  1690.         if( options&1 && (p=strchr(av[i],'/'))) {
  1691.             do {
  1692.                 c = *p;
  1693.                 *p = '\0';
  1694.                 if (lock=CreateDir(av[i]))
  1695.                     UnLock(lock);
  1696.                 *p = c;
  1697.             } while(p=strchr(++p,'/'));
  1698.         }
  1699.  
  1700.         /* allow trailing slash */
  1701.         if (lastch(av[i]) == '/' )
  1702.             av[i][strlen(av[i])-1] = '\0';
  1703.  
  1704.         /* Okay, sub-directories should exist, now try normal mkdir. */
  1705.  
  1706.         if (lock=CreateDir(av[i]))
  1707.             UnLock(lock);
  1708.         else
  1709.             pError(av[i]);
  1710.  
  1711.     }
  1712.  
  1713.     return 0;
  1714. }
  1715.  
  1716. int
  1717. do_mv( void )
  1718. {
  1719.     char *dest, buf[256];
  1720.     int dirflag, i, len;
  1721.  
  1722.     dirflag=isdir(dest=av[--ac]);
  1723.     if (ac>3 && !dirflag) { ierror(dest, 507); return (-1); }
  1724.     for (i=1; i<ac; ++i) {
  1725.         strcpy(buf, dest);
  1726.  
  1727.         /* source: remove trailing slash */
  1728.         if ((len=strlen(av[i]))>1 && av[i][len-1]=='/' && av[i][len-2]!=':' && av[i][len-2]!='/')
  1729.             av[i][len-1] = '\0';
  1730.  
  1731.         /* destination: remove trailing slash */
  1732.         if ((len=strlen(buf))>1 && buf[len-1]=='/' && buf[len-2]!=':' && buf[len-2]!='/')
  1733.             buf[len-1] = '\0';
  1734.  
  1735.         if (dirflag && stricmp(av[i],buf))
  1736.              AddPart(buf, FilePart(av[i]), 255L);
  1737.  
  1738.         if (Rename(av[i], buf)==0) {
  1739.             pError(av[i]);
  1740.             if (!(options&1))
  1741.                 return -1;
  1742.         }
  1743.         else {
  1744.             clear_archive_bit( buf );
  1745.             if (options&2) {
  1746.                 /*printf("Renaming %s as %s\n",av[i],buf);*/
  1747.                 printf(" %s...%s\n",av[i],dirflag?"moved":"renamed");
  1748.             }
  1749.         }
  1750.     }
  1751.     return 0;
  1752. }
  1753.  
  1754. static char *searchstring;
  1755. static char docr;
  1756.  
  1757. #if 0
  1758. int
  1759. all_args( int (*action)FUNCARG(long,char*,char*), int dirsflag )
  1760. {
  1761.     int  i;
  1762.     long mask= SCAN_FILE;
  1763.  
  1764.     if( options&1 )
  1765.         mask |= SCAN_RECURSE;
  1766.     if( dirsflag )
  1767.         mask |= SCAN_DIR;
  1768.  
  1769.     for ( i=1; i<ac && !dobreak(); ++i)
  1770.         if (isdir(av[i])) {
  1771.             if (options & 1)
  1772.                 newrecurse(mask, av[i], action);
  1773.             if (dirsflag)
  1774.                 (*action)(SCAN_DIR,av[i],av[i]);
  1775.         } else
  1776.             (*action)(SCAN_FILE,av[i],av[i]);
  1777.     if(docr) printf("\n"),docr=0;
  1778.     dobreak();
  1779.     return 0;
  1780. }
  1781. #endif
  1782.  
  1783. /* this is all_args() but with a user definable range from n to m */
  1784. int
  1785. all_args_n2m( int (*action)FUNCARG(long,char*,char*), int dirsflag, int aa_from, int aa_to )
  1786. {
  1787.     int  i;
  1788.     long mask= SCAN_FILE;
  1789.  
  1790.     if( options&1 )
  1791.         mask |= SCAN_RECURSE;
  1792.     if( dirsflag )
  1793.         mask |= SCAN_DIR;
  1794.  
  1795.     for ( i=aa_from; i<aa_to && !dobreak(); ++i)
  1796.         if (isdir(av[i])) {
  1797.             if (options & 1)
  1798.                 newrecurse(mask, av[i], action);
  1799.             if (dirsflag)
  1800.                 (*action)(SCAN_DIR,av[i],av[i]);
  1801.         } else
  1802.             (*action)(SCAN_FILE,av[i],av[i]);
  1803.     if(docr) printf("\n"),docr=0;
  1804.     dobreak();
  1805.     return 0;
  1806. }
  1807.  
  1808. int
  1809. all_args( int (*action)FUNCARG(long,char*,char*), int dirsflag )
  1810. {
  1811.     return( all_args_n2m(action,dirsflag,1,ac) );
  1812. }
  1813.  
  1814. #define SEARCH_REC   1
  1815. #define SEARCH_CASE  2
  1816. #define SEARCH_WILD  4
  1817. #define SEARCH_NUM   8
  1818. #define SEARCH_EXCL  16
  1819. #define SEARCH_QUIET 32
  1820. #define SEARCH_VERB  64
  1821. #define SEARCH_BIN   128
  1822. #define SEARCH_FILE  256
  1823. #define SEARCH_ABORT 512
  1824. #define SEARCH_LEFT  1024
  1825. #define SEARCH_ONLY  2048
  1826.  
  1827. /* added by amk, not yet implemented */
  1828. #define SEARCH_STYLE 4096    /* alternative style, inspired by GMD */
  1829. #define SEARCH_ONCE  8192    /* only show first pattern match per file */
  1830.  
  1831. static int abort_search;
  1832. static char lowbuf[256], file_name, file_cr;
  1833.  
  1834. static int
  1835. search_file( long mask, char *s, char *fullpath )
  1836. {
  1837.     PATTERN *pat;
  1838.     FILE *fi;
  1839.     char *p, *q;
  1840.     int nocasedep, lctr, len, excl=((options & 16) !=0 ), yesno;
  1841.     char buf[256], searchit[120], first, left;
  1842.  
  1843.     if( abort_search )
  1844.         return 0;
  1845.  
  1846.     nocasedep=!(options & SEARCH_CASE);
  1847.     lctr= docr= file_name= file_cr= 0;
  1848.     if (!(options & (SEARCH_QUIET|SEARCH_FILE))) {
  1849.         if( options & SEARCH_VERB )
  1850.             printf("Examining %s ...\n",fullpath);
  1851.         else
  1852.             printf("\015Examining %s ...\033[K",fullpath), docr=1;
  1853.         fflush( stdout );
  1854.     }
  1855.  
  1856.     strcpy(searchit,searchstring);
  1857.     if (options & SEARCH_WILD) strcat(searchit,"\n");
  1858.     len=strlen(searchit);
  1859.     if (nocasedep) strupr(searchit);
  1860.     first = *searchit;
  1861.  
  1862.     if( strcmp("STDIN",s) && !(options&SEARCH_WILD) && !excl ||
  1863.                  options&SEARCH_BIN )
  1864.         if( quicksearch(s,nocasedep,searchit) )
  1865.             return 0;
  1866.  
  1867.     if( options&SEARCH_BIN )
  1868.         { fprintf(stderr,"Out of memory\n"); return 20; }
  1869.  
  1870.     if(!(pat=compare_preparse( searchit, options&SEARCH_CASE )))
  1871.         { fprintf(stderr,"Invalid pattern\n"); return 20; }
  1872.  
  1873.     fi = strcmp("STDIN",s) ?  fopen(s,"r") : stdin;
  1874.     if (fi==NULL) { pError(s); return 20; }
  1875.  
  1876.     prepscroll(0);
  1877.  
  1878.     while (fgets(buf,256,fi) && !dobreak()) {
  1879.         lctr++; left=1;
  1880.         if (options & SEARCH_WILD)
  1881.             yesno=compare_ok(pat, p=buf);
  1882.         else {
  1883.             if (nocasedep) {
  1884.                 strcpy(lowbuf,buf);
  1885.                 strupr(lowbuf);
  1886.                 p=lowbuf;
  1887.             } else
  1888.                 p=buf;
  1889.             q=p;
  1890.             while ((p=index(p,first)) && strncmp(p++,searchit,len)) ;
  1891.             yesno= (p!=NULL);
  1892.             left = --p - q;
  1893.         }
  1894.         if( yesno ^ excl )
  1895.             if(!(options&SEARCH_ONLY)|| !isalphanum(p[-1])&&!isalphanum(p[len]))
  1896.                 if( found(buf, lctr, 0, s, left ) )
  1897.                     break;
  1898.     }
  1899.     compare_free(pat);
  1900.     if (fi!=stdin) fclose (fi);
  1901.     if( file_cr ) printf("\n");
  1902.     return 0;
  1903. }
  1904.  
  1905. int qcd_flag, qcd_offs;
  1906.  
  1907. #define READCHUNK 60000
  1908.  
  1909. static int
  1910. quicksearch( char *name, int nocasedep, char *pattern )
  1911. {
  1912.     int i, ptrn=strlen(pattern);
  1913.     char ut[256], *buffer, *lend;
  1914.     char *uptab=ut, *get, c, *lpos, *lstart;
  1915.     int len, lnum, qcd=qcd_flag, repeat=(qcd==2 && qcd_offs!=0), buflen;
  1916.     int sofar, got;
  1917.     BPTR fh;
  1918.  
  1919. #ifdef AZTEC_C
  1920.     while(0) while(0) c=c=0, uptab=uptab=ut, get=get=NULL;
  1921. #endif
  1922.  
  1923.     qcd_flag=0;
  1924.     if( !(fh=Open(name,MODE_OLDFILE))) {
  1925.         i=(long)IoErr(), docr=0;
  1926.         printf("\n");
  1927.         ierror(name,i);
  1928.         return 1;
  1929.     }
  1930.     len=filesize( name );
  1931.     buflen=len+3;
  1932.     if( !(buffer=(void *)AllocMem(buflen,0))) { Close(fh); return 0; }
  1933.     sofar=0;
  1934.     do {
  1935.         got=Read( fh, (char *)buffer+sofar, READCHUNK);
  1936.         sofar+=got;
  1937.     } while( got==READCHUNK );
  1938.     Close( fh);
  1939.     if( sofar != len ) {
  1940.         FreeMem( buffer, buflen );
  1941.         pError(pattern); return 1;
  1942.     }
  1943.     if(buffer[len-1]!='\n')
  1944.         buffer[len++]='\n';
  1945.  
  1946.     if( nocasedep )
  1947.         strupr( pattern );
  1948.  
  1949.     if( !qcd )
  1950.         prepscroll(0);
  1951.  
  1952.     for( i=0; i<256; i++ ) uptab[i]=i;
  1953.     if( nocasedep ) for( i='a'; i<='z'; i++ ) uptab[i]=i-'a'+'A';
  1954. retry:
  1955.     c = *pattern, buffer[len]=c, buffer[len+1]=c;
  1956.     get= (qcd==2) ? buffer+qcd_offs : buffer;
  1957.     if( qcd==1 ) qcd_offs=0;
  1958.  
  1959.     lpos=lstart=buffer, lnum=1;
  1960.     for( ;; ) {
  1961.         do ; while( uptab[*get++]!=c );
  1962.         if( --get>=buffer + len )
  1963.             break;
  1964.         for( i=1; i<ptrn; i++ )
  1965.             if( uptab[get[i]]!=pattern[i] )
  1966.                 break;
  1967.         if( i==ptrn ) {
  1968.             for( ;lpos<get; lpos++ )
  1969.                 if( *lpos=='\n' )
  1970.                     lstart=lpos+1, lnum++;
  1971.             for( lend=lstart+1; *lend!='\n'; lend++ ) ;
  1972.             if( qcd ) {
  1973.                 if( get[-1]==':' || get[-1]=='/' ||
  1974.                       lpos==lstart && lend[-1]==':' ) {
  1975.                     char *tmp;
  1976.                     for( tmp=get+ptrn; *tmp&& *tmp!='\n'&& *tmp!='/'; tmp++ );
  1977.                     if( *tmp!='/' ) {
  1978.                         *lend=0;
  1979.                         strncpy(pattern,lstart,79);
  1980.                         qcd_offs=lend-buffer;
  1981.                         FreeMem( buffer, buflen );
  1982.                         return 2;
  1983.                     }
  1984.                 } else 
  1985.                     lend=lpos+1;
  1986.             } else {
  1987.                 *lend=0;
  1988.                 if(!(options&SEARCH_ONLY) ||
  1989.                      !isalphanum(lpos[-1])&&!isalphanum(lpos[ptrn]))
  1990.                     if(found(lstart, lnum, get-buffer, name, lpos==lstart ))
  1991.                         break;
  1992.                 *lend='\n';
  1993.             }
  1994.             get=lend+1;
  1995.         } else
  1996.             get++;
  1997.     }
  1998.     if( repeat )  { repeat=0; qcd_offs=0; goto retry; }
  1999.     if( file_cr ) { printf("\n"); quickscroll(); }
  2000.     FreeMem( buffer, buflen );
  2001.     return 1;
  2002. }
  2003.  
  2004. static int
  2005. found( char *lstart, int lnum, int loffs, char *name, char left )
  2006. {
  2007.     int fileabort=0;
  2008.  
  2009.     if( (options&SEARCH_LEFT) && !left)
  2010.         return 0;
  2011.  
  2012.     if ( docr )
  2013.         { quickscroll(); printf("\n"); docr=0; }
  2014.  
  2015.     if( options&SEARCH_FILE ) {
  2016.         file_cr=1;
  2017.         if( !file_name )
  2018.             printf("%s",name), file_name=1;
  2019.         if( options&SEARCH_NUM )
  2020.             fileabort=1;
  2021.         else
  2022.             printf(" %d",lnum);
  2023.     } else if( options & SEARCH_BIN ) {
  2024.         if (!(options & SEARCH_NUM))
  2025.             printf("Byte offset %d\n",loffs);
  2026.         else
  2027.             printf("%d\n",loffs);
  2028.         quickscroll();
  2029.     } else {
  2030.         if (!(options & SEARCH_NUM))
  2031.             printf("%4d ",lnum);
  2032.         printf((lstart[strlen(lstart)-1]=='\n')?"%s":"%s\n",lstart);
  2033.         quickscroll();
  2034.     }
  2035.     abort_search= options&SEARCH_ABORT;
  2036.     return dobreak() || fileabort || abort_search;
  2037. }
  2038.  
  2039. int
  2040. do_search( void )
  2041. {
  2042.     if(!IsInteractive(Output())) options |= SEARCH_VERB;
  2043.     abort_search=0;
  2044.     searchstring=av[--ac];
  2045.     all_args(search_file, 0);
  2046.     return 0;
  2047. }
  2048.  
  2049. #if 0
  2050. /* do_grep() is just do_search() with a modified all_args() */
  2051. int
  2052. do_grep( void )
  2053. {
  2054.     if(!IsInteractive(Output())) options |= SEARCH_VERB;
  2055.     abort_search=0;
  2056.     searchstring=av[1];
  2057.     all_args_n2m(search_file, 0, 2, ac);
  2058.     return 0;
  2059. }
  2060. #endif
  2061.  
  2062. static BOOL rm_error_abort = FALSE;
  2063. static int rm_file( long mask, char *file, char *fullpath )
  2064. {
  2065.     if (rm_error_abort)
  2066.         return(20);
  2067.  
  2068.     if ( *file && file[strlen(file)-1]=='/' ) {
  2069.         file[strlen(file)-1]=0;
  2070.     }
  2071.     if (options&16 || has_wild) {
  2072.         fprintf(stdout," %s...",fullpath);
  2073.         fflush(stdout);
  2074.     }
  2075.     if (options&2 || options&4) {
  2076.         SetProtection(file,0L);
  2077.     }
  2078.     if (!DeleteFile(file)) {
  2079.         pError(file);
  2080.         if (options & 8) {
  2081.             rm_error_abort = TRUE;
  2082.             return 20;
  2083.         }
  2084.     } else if (options&16 || has_wild)
  2085.         fprintf(stdout,"Deleted\n");
  2086.  
  2087.     return 0;
  2088. }
  2089.  
  2090. int
  2091. do_rm( void )
  2092. {
  2093.     rm_error_abort = FALSE;
  2094.     all_args( rm_file, 1);
  2095.     rm_error_abort = FALSE;
  2096.     return 0;
  2097. }
  2098.  
  2099.  
  2100. int
  2101. do_history( void )
  2102. {
  2103.     HIST *hist;
  2104.     int i = H_tail_base;
  2105.     int len = av[1] ? strlen(av[1]) : 0;
  2106.     char buf[250];
  2107.  
  2108.     if( options&2 ) {
  2109.         while( safegets(buf,stdin) )
  2110.             add_history(buf);
  2111.         return 0;
  2112.     }
  2113.  
  2114.     for (hist = H_tail; hist && !dobreak(); hist = hist->prev, i++)
  2115.         if (len == 0 || !strncmp(av[1], hist->line, len))
  2116.             if( options&1 )
  2117.                 printf("%s\n", hist->line);
  2118.             else
  2119.                 printf("%3d %s\n", i, hist->line);
  2120.     return 0;
  2121. }
  2122.  
  2123. int
  2124. do_mem( void )
  2125. {
  2126.     static long clast, flast;
  2127.     long cfree, ffree, cfreel, ffreel, i;
  2128.     char *desc="Free", *mem;
  2129.  
  2130.     if( options&32 )
  2131.         for( i=0; i<10; i++ )
  2132.             if(mem=(char*)AllocMem(0x7fffffff,0))
  2133.                 FreeMem(mem,0x7fffffff);
  2134.  
  2135.     Forbid();
  2136.     cfree = AvailMem (MEMF_CHIP);
  2137.    cfreel= AvailMem (MEMF_CHIP|MEMF_LARGEST);
  2138.     ffree = AvailMem (MEMF_FAST);
  2139.    ffreel= AvailMem (MEMF_FAST|MEMF_LARGEST);
  2140.     Permit();
  2141.     if( options&8 ) {
  2142.         clast=cfree, flast=ffree;
  2143.         return 0;
  2144.     }
  2145.     if( options&16 )
  2146.         cfree=clast-cfree, ffree=flast-ffree, desc="Used";
  2147.     if( options&4 ) {
  2148.         if     ( options & 1 ) printf("%lu\n",cfree);
  2149.         else if( options & 2 ) printf("%lu\n",ffree);
  2150.         else                   printf("%lu\n",cfree+ffree);
  2151.     } else {
  2152.         if     ( options & 1 ) {
  2153.             printf("Free CHIP memory: %10s",itoa(cfree));
  2154.             do_printmax( cfreel ); }
  2155.         else if( options & 2 ) {
  2156.             printf("Free FAST memory: %10s",itoa(ffree));
  2157.             do_printmax( ffreel ); }
  2158.         else {
  2159.             if(ffree) {
  2160.                 printf("FAST memory: %10s",itoa(ffree));
  2161.             do_printmax( ffreel );
  2162.                 printf("CHIP memory: %10s",itoa(cfree));
  2163.                 do_printmax( cfreel );
  2164.             }
  2165.             printf("Total  %s: %10s",desc,itoa(cfree+ffree));
  2166.          do_printmax(max(cfreel,ffreel));
  2167.         }
  2168.     }
  2169.     return 0;
  2170. }
  2171.  
  2172. void do_printmax( int free )
  2173. {
  2174.     if(!( options&16 )) printf(" (max %10s)",itoa(free));
  2175.     putchar('\n');
  2176. }
  2177.  
  2178. int
  2179. do_forline( void )
  2180. {
  2181.     char vname[33], buf[256], *cstr;
  2182.     int lctr;
  2183.     FILE *f;
  2184.  
  2185.     strcpy(vname,av[1]);
  2186.     if( !strcmp(av[2],"STDIN") )
  2187.         f=stdin;
  2188.     else 
  2189.         if(!(f=fopen(av[2],"r"))) { pError(av[2]); return 20; }
  2190.  
  2191.     lctr=0;
  2192.     ++H_stack;
  2193.     cstr = compile_av (av, 3, ac, ' ', 0);
  2194.     while (fgets(buf,256,f) && !dobreak() && !breakcheckd()) {
  2195.         buf[strlen(buf)-1]='\0';    /* remove CR */
  2196.         lctr++;
  2197.         set_var(LEVEL_SET | LEVEL_LOCAL, vname, buf);
  2198.         sprintf(buf,"%d",lctr);
  2199.         set_var(LEVEL_SET | LEVEL_LOCAL, v_linenum, buf);
  2200.         exec_command(cstr);
  2201.     }
  2202.     if( f!=stdin ) fclose(f);
  2203.     --H_stack;
  2204.     free (cstr);
  2205.     if( lctr ) {
  2206.         unset_var (LEVEL_SET, vname);
  2207.         unset_var (LEVEL_SET, v_linenum);
  2208.     }
  2209.     return 0;
  2210. }
  2211.  
  2212. int
  2213. do_fornum( void )
  2214. {
  2215.     char vname[33], buf[16];
  2216.     int n1, n2, step, i=1, verbose, runs=0;
  2217.     char *cstr;
  2218.  
  2219.     verbose=(options & 1);
  2220.     strcpy(vname,av[i++]);
  2221.     n1=myatoi(av[i++],-32767,32767); if (atoierr) return 20;
  2222.     n2=myatoi(av[i++],-32767,32767); if (atoierr) return 20;
  2223.     if (options & 2) {
  2224.         step=myatoi(av[i++],-32767,32767); if (atoierr) return 20;
  2225.     } else
  2226.         step=1;
  2227.     ++H_stack;
  2228.     cstr = compile_av (av, i, ac, ' ', 0);
  2229.     for (i=n1; (step>=0 ? i<=n2 : i>=n2) && !CHECKBREAK() && !breakcheckd();
  2230.          i+=step, runs++) {
  2231.         if (verbose) fprintf(stderr, "fornum: %d\n", i);
  2232.         sprintf(buf,"%d",i);
  2233.         set_var (LEVEL_SET | LEVEL_LOCAL, vname, buf);
  2234.         exec_command(cstr);
  2235.     }
  2236.     --H_stack;
  2237.     free (cstr);
  2238.     if( runs )
  2239.         unset_var (LEVEL_SET, vname);
  2240.     return 0;
  2241. }
  2242.  
  2243. /*
  2244.  * foreach var_name  ( str str str str... str ) commands
  2245.  * spacing is important (unfortunately)
  2246.  *
  2247.  * ac=0    1 2 3 4 5 6 7
  2248.  * foreach i ( a b c ) echo $i
  2249.  * foreach i ( *.c ) "echo -n "file ->";echo $i"
  2250.  */
  2251.  
  2252. int
  2253. do_foreach( void )
  2254. {
  2255.     int cstart, cend;
  2256.     char *cstr, vname[33];
  2257.     char **fav;
  2258.     int i=1, verbose;
  2259.  
  2260.     verbose=(options & 1);
  2261.     strcpy(vname, av[i++]);
  2262.     if (*av[i] == '(') i++;
  2263.     cstart = i;
  2264.     while (i<ac && *av[i] != ')') i++;
  2265.     if (i > ac) { fprintf(stderr,"')' expected\n"); return 20; }
  2266.     ++H_stack;
  2267.     cend = i;
  2268.  
  2269.     fav = (char **)salloc(sizeof(char *) * (ac));
  2270.     for (i = cstart; i < cend; ++i) fav[i] = av[i];
  2271.  
  2272.     cstr = compile_av (av, cend + 1, ac, ' ', 0);
  2273.  
  2274.     for (i = cstart; i<cend && !CHECKBREAK() && !breakcheckd() && !breakchecke(); ++i) {
  2275.         set_var (LEVEL_SET | LEVEL_LOCAL, vname, fav[i]);
  2276.         if (verbose) fprintf(stderr, "foreach: %s\n", fav[i]);
  2277.         execute(cstr);
  2278.     }
  2279.     --H_stack;
  2280.     free (fav);
  2281.     free (cstr);
  2282.     if( cstart<cend)
  2283.         unset_var (LEVEL_SET, vname);
  2284.     return 0;
  2285. }
  2286.  
  2287. int
  2288. do_forever( char *str )
  2289. {
  2290.     int rcode = 0;
  2291.     char *ptr = next_word( str );
  2292.  
  2293.     ++H_stack;
  2294.     for (;;) {
  2295.         if (CHECKBREAK() || breakcheckd()) { rcode = 20; break; }
  2296.         if (exec_command (ptr) > 0) {
  2297.             str = get_var(LEVEL_SET, v_lasterr);
  2298.             rcode = (str) ? atoi(str) : 20;
  2299.             break;
  2300.         }
  2301.     }
  2302.     --H_stack;
  2303.     return rcode;
  2304. }
  2305.  
  2306. extern struct IntuitionBase *IntuitionBase;
  2307.  
  2308.  
  2309. int
  2310. do_window( void )
  2311. {
  2312. #if 1
  2313.     long x = -1, y = -1, w = -1, h = -1, maxwidth, maxheight;
  2314. #else
  2315.     long x = -1, y = -1, w = -1, h = -1, maxwidth, maxheight, arg[5];
  2316.     int i;
  2317. #endif
  2318.  
  2319.     if(options & 32) { /* -q */
  2320.         struct Screen *scrn;
  2321.         struct Window *window;
  2322.         ULONG ibase_lock;
  2323.         char **ibase_list=NULL;
  2324.         long i,ibase_num=0;
  2325.         char fmt[256];
  2326.  
  2327.         newwidth(); /**/    /* get current window width */
  2328.  
  2329.         ibase_lock = LockIBase(0);
  2330.  
  2331.         for (scrn=IntuitionBase->FirstScreen; scrn; scrn=scrn->NextScreen) {
  2332.  
  2333.             struct List *list;
  2334.             struct Node *node;
  2335.             UBYTE PubNameBuf[MAXPUBSCREENNAME+4] = "";
  2336.  
  2337.             list = LockPubScreenList();
  2338.             for (node = list->lh_Head; node->ln_Succ; node = node->ln_Succ) {
  2339.                 if (((struct PubScreenNode *)node)->psn_Screen == scrn)
  2340.                     sprintf(PubNameBuf," [%s]",node->ln_Name);
  2341.             }
  2342.             UnlockPubScreenList();
  2343.  
  2344.             sprintf(fmt,"Screen %c%.*s%c%s (%d,%d,%dx%dx%d):\n",
  2345.                 scrn->Title ? '\"' : '(',
  2346.                 (options&64) ? 128 : (((w_width-36-strlen(PubNameBuf)) > 0) ? (w_width-36-strlen(PubNameBuf)) : 30),
  2347.                 scrn->Title ? scrn->Title : "no title",
  2348.                 scrn->Title ? '\"' : ')',
  2349.                 PubNameBuf,
  2350.                 scrn->LeftEdge,
  2351.                 scrn->TopEdge,
  2352.                 scrn->Width,
  2353.                 scrn->Height,
  2354.                 scrn->BitMap.Depth
  2355.             );
  2356.             add_array_list(&ibase_list,&ibase_num,fmt);
  2357.  
  2358.             for (window=scrn->FirstWindow; window; window=window->NextWindow) {
  2359.                 sprintf(fmt,"   win %c%.*s%c (%d,%d,%dx%d)\n",
  2360.                     window->Title ? '\"' : '(',
  2361.                     (options&64) ? 128 : w_width-32,
  2362.                     window->Title ? window->Title : "no title",
  2363.                     window->Title ? '\"' : ')',
  2364.                     window->LeftEdge,
  2365.                     window->TopEdge,
  2366.                     window->Width,
  2367.                     window->Height
  2368.                 );
  2369.                 add_array_list(&ibase_list,&ibase_num,fmt);
  2370.             }
  2371.  
  2372.             if (scrn->NextScreen)
  2373.                 add_array_list(&ibase_list,&ibase_num,"\n");
  2374.         }
  2375.  
  2376.         UnlockIBase(ibase_lock);
  2377.  
  2378.         for(i=0; i<ibase_num; i++)
  2379.             printf("%s",ibase_list[i]);
  2380.  
  2381.         free_array_list(ibase_list,ibase_num);
  2382.  
  2383.         return 0;
  2384.     }
  2385.  
  2386.     if( o_nowindow || !Mywindow )
  2387.         return 20;
  2388.  
  2389.     maxwidth = Mywindow->WScreen->Width;
  2390.     maxheight= Mywindow->WScreen->Height;
  2391.  
  2392.     if( options&1 )
  2393.         x=Mywindow->LeftEdge,y=Mywindow->TopEdge,w=Mywindow->MinWidth,h=Mywindow->MinHeight;
  2394.     if( options&2 ) x=y=0, w=maxwidth, h=maxheight;
  2395.     if( options&4 ) WindowToFront(Mywindow);
  2396.     if( options&8 ) WindowToBack(Mywindow);
  2397.     if( options&16) ActivateWindow(Mywindow);
  2398.  
  2399.     if( ac == 5 ) {
  2400. #if 1
  2401.         x = myatoi(av[1],-2,maxwidth-Mywindow->MinWidth); if (atoierr) return 20;
  2402.         y = myatoi(av[2],-2,maxheight-Mywindow->MinHeight); if (atoierr) return 20;
  2403.         w = myatoi(av[3],-2,maxwidth); if (atoierr) return 20;
  2404.         h = myatoi(av[4],-2,maxheight); if (atoierr) return 20;
  2405. #else
  2406.         for(i=1; i<5; i++) {
  2407.             arg[i] = myatoi(av[i],-2,32767); if (atoierr) return 20;
  2408.         }
  2409.         x=arg[1]; y=arg[2]; w=arg[3]; h=arg[4];
  2410. #endif
  2411.  
  2412.         if( x==-1 ) x=0; else if( x==-2 ) x=Mywindow->LeftEdge;
  2413.         if( y==-1 ) y=0; else if( y==-2 ) y=Mywindow->TopEdge;
  2414.         if( w==-1 ) w=maxwidth; else if( w==-2 ) w=Mywindow->Width;
  2415.         if( h==-1 ) h=maxheight; else if( h==-2 ) h=Mywindow->Height;
  2416.     }
  2417.     else if ( ac != 1 ) {
  2418.         fprintf(stderr,"Usage: window <pos_x> <pos_y> <width> <height>\n");
  2419.         fprintf(stderr,"   or  window -<options>\n");
  2420.         return 20;
  2421.     }
  2422.  
  2423.     if( w != -1 ) {
  2424.         int i;
  2425. #if 1
  2426.         if ( x+w>maxwidth ) x=maxwidth-w;
  2427.         if ( y+h>maxheight ) y=maxheight-h;
  2428.         if( w<Mywindow->MinWidth  ) w=Mywindow->MinWidth;
  2429.         if( h<Mywindow->MinHeight ) h=Mywindow->MinHeight;
  2430. #else
  2431.         if ( x+w>maxwidth || y+h>maxheight ) {
  2432.             ierror(NULL, 500);
  2433.             return 20;
  2434.         }
  2435. #endif
  2436.         if( Mywindow->LeftEdge+w > maxwidth ) {
  2437.             MoveWindow(Mywindow, x-Mywindow->LeftEdge, 0);
  2438.             SizeWindow(Mywindow, w-Mywindow->Width, 0); }
  2439.         else {
  2440.             SizeWindow(Mywindow, w-Mywindow->Width, 0);
  2441.             MoveWindow(Mywindow, x-Mywindow->LeftEdge, 0); }
  2442.  
  2443.         if( Mywindow->TopEdge+h > maxheight ) {
  2444.             MoveWindow(Mywindow, 0, y-Mywindow->TopEdge);
  2445.             SizeWindow(Mywindow, 0, h-Mywindow->Height); }
  2446.         else {
  2447.             SizeWindow(Mywindow, 0, h-Mywindow->Height);
  2448.             MoveWindow(Mywindow, 0, y-Mywindow->TopEdge); }
  2449.  
  2450.         for( i=0; i<10; i++ ) {
  2451.             if(  Mywindow->LeftEdge==x && Mywindow->TopEdge==y &&
  2452.                  Mywindow->Width   ==w && Mywindow->Height ==h )
  2453.                 break;
  2454.             Delay(5);
  2455.         }
  2456.     } else
  2457.         Delay(25); /* pause 1/2 sec. before trying to print */
  2458.         /* Delay(20); */ /* pause 1/2 sec. before trying to print */
  2459.  
  2460.     Delay(25);
  2461.     /* Delay(10); */
  2462.     /* printf("\014"); */
  2463.     return 0;
  2464. }
  2465.  
  2466. static void
  2467. setsystemtime(struct DateStamp *ds)
  2468. {
  2469.     struct timerequest tr;
  2470.     long secs= ds->ds_Days*86400+ds->ds_Minute*60+ds->ds_Tick/TICKS_PER_SECOND;
  2471.  
  2472.     if (OpenDevice(TIMERNAME, UNIT_VBLANK,(struct IORequest *)&tr, 0L)) {
  2473.         fprintf(stderr,"Clock error: can't open timer device\n");
  2474.         return;
  2475.     }
  2476.  
  2477.     tr.tr_node.io_Message.mn_Node.ln_Type = NT_MESSAGE;
  2478.     tr.tr_node.io_Message.mn_Node.ln_Pri = 0L;
  2479.     tr.tr_node.io_Message.mn_Node.ln_Name = NULL;
  2480.     tr.tr_node.io_Message.mn_ReplyPort = NULL;
  2481.     tr.tr_node.io_Command = TR_SETSYSTIME;
  2482.     tr.tr_time.tv_secs = secs;
  2483.     tr.tr_time.tv_micro = 0L;
  2484.     if (DoIO ((struct IORequest *)&tr))
  2485.         fprintf(stderr,"Clock error: can't talk to timer device\n");
  2486.     CloseDevice ((struct IORequest *)&tr);
  2487. }
  2488.  
  2489.  
  2490. static char tday[LEN_DATSTRING+1];    /* not sure, if +1 (null byte) is neccessary */
  2491.  
  2492. char *
  2493. dates( struct DateStamp *dss, int flags )
  2494. {
  2495.     static char timestr[2*LEN_DATSTRING+3];
  2496.     char tdate[LEN_DATSTRING+1], ttime[LEN_DATSTRING+1];
  2497.     struct DateTime dt;
  2498.     struct DateStamp *myds;
  2499.     char *dp,*tp;
  2500.     int slen;
  2501.  
  2502.     dt.dat_Format  = FORMAT_DOS;    /* bug in DOS, always localized :-( */
  2503.     dt.dat_StrDay  = tday;
  2504.     dt.dat_StrDate = tdate;
  2505.     dt.dat_StrTime = ttime;
  2506.     dt.dat_Flags   = flags ? DTF_SUBST : 0;
  2507.     dt.dat_Stamp   = *dss;
  2508.  
  2509.     myds = &(dt.dat_Stamp);
  2510.  
  2511.     if(  myds->ds_Days<0   || myds->ds_Days>36500 ||
  2512.          myds->ds_Minute<0 || myds->ds_Minute>1440 ||
  2513.          myds->ds_Tick<0   || myds->ds_Tick>3000 || !DateToStr(&dt) )
  2514.         strcpy(tdate,"---------"), strcpy(ttime,"--------");
  2515.  
  2516. #if 0
  2517.     ttime[8] = '\0';
  2518.     sprintf(timestr,"%-9s %-8s",tdate,ttime);
  2519. #endif
  2520.  
  2521.     /* strip off leading spaces from 'tdate' -> result in 'dp' */
  2522.  
  2523.     for (dp=tdate; dp && *dp && (*dp==' ' || *dp=='\t'); dp++)
  2524.         ;
  2525.  
  2526.     /* strip off trailing spaces from 'dp'
  2527.  
  2528.     for (slen=strlen(dp)-1; slen>=0 && (dp[slen]==' ' || dp[slen]=='\t'); --slen)
  2529.         dp[slen] = '\0'; */
  2530.  
  2531.     /* strip off leading spaces from 'ttime' -> result in 'tp' */
  2532.  
  2533.     for (tp=ttime; tp && *tp && (*tp==' ' || *tp=='\t'); tp++)
  2534.         ;
  2535.  
  2536.     /* strip off trailing spaces from 'tp'
  2537.  
  2538.     for (slen=strlen(tp)-1; slen>=0 && (tp[slen]==' ' || tp[slen]=='\t'); --slen)
  2539.         tp[slen] = '\0'; */
  2540.  
  2541.     /* month name > 3 chars? (bug in french locale) */
  2542.  
  2543.     while (strlen(dp) > 9)
  2544.         strdel(dp,6,1);
  2545.  
  2546.     sprintf(timestr,"%9.9s %8.8s",dp,tp);
  2547.  
  2548.     timestr[18] = '\0';    /* protection against bad timestamped files */
  2549.     return timestr;
  2550. }
  2551.  
  2552. /*
  2553.  * returns difference in msecs between two TIMEVALS (GMD)
  2554.  */
  2555.  
  2556. long tv_diff (struct timeval * tv1, struct timeval * tv2)
  2557. {
  2558.     long val;
  2559.  
  2560.     val = ((long) tv2->tv_secs - (long) tv1->tv_secs) * 1000L;
  2561.     val += (((long) tv2->tv_micro) - ((long) tv1->tv_micro)) / 1000L;
  2562.  
  2563.     return val;
  2564. }
  2565.  
  2566. /*
  2567.  * given a DateStamp structure , returns an updated TIMEVAL (GMD)
  2568.  */
  2569.  
  2570. void dss2tv (struct DateStamp * t1, struct timeval * tv)
  2571. {
  2572.     ULONG secs;
  2573.  
  2574.     secs = t1->ds_Days * 24 * 60 * 60;
  2575.     secs += t1->ds_Minute * 60;
  2576.     secs += t1->ds_Tick / TICKS_PER_SECOND;
  2577.  
  2578.     tv->tv_secs = secs;
  2579.     tv->tv_micro = (t1->ds_Tick % TICKS_PER_SECOND) * (1000000 / TICKS_PER_SECOND);
  2580. }
  2581.  
  2582. /*
  2583.  * tv2dss ; converts a timeval structure to a DateStamp structure (GMD)
  2584.  */
  2585.  
  2586. void tv2dss (struct timeval * tv, struct DateStamp * dss)
  2587. {
  2588.     long rem;
  2589.  
  2590.     dss->ds_Days = tv->tv_secs / (24 * 60 * 60);
  2591.     rem = tv->tv_secs % (24 * 60 * 60);    /* secs in last day */
  2592.  
  2593.     dss->ds_Minute = rem / 60;
  2594.     rem = rem % 60;        /* secs in last minute */
  2595.  
  2596.     rem = (rem * 1000) + (tv->tv_micro / 1000);    /* msecs in last minute */
  2597.  
  2598.     dss->ds_Tick = rem / (1000 / TICKS_PER_SECOND);    /* ticks in last minute */
  2599. }
  2600.  
  2601. /* code for battery-clock by Gary Duncan (GMD) */
  2602.  
  2603. int
  2604. do_date (void)
  2605. {
  2606.     static struct DateStamp dss_s; /* set by -s option */
  2607.     static struct timeval tv;
  2608.     struct DateStamp dss;
  2609.     struct DateTime dt;
  2610.     int i = 1;
  2611.  
  2612.     dt.dat_Format = FORMAT_DOS;
  2613.     if (ac == 1) {
  2614.         DateStamp(&dss);
  2615.         if (options & 4) {  /* its read-battery-clock time; GMD */
  2616.             struct timeval tv_batt;
  2617.             if (BattClockBase==NULL) {
  2618.                 fprintf(stderr,"No Battery Clock\n");
  2619.                 return 0;
  2620.             }
  2621.             tv_batt.tv_micro = 0;
  2622.             tv_batt.tv_secs  = ReadBattClock();
  2623.             tv2dss(&tv_batt,&dss);
  2624.         }
  2625.  
  2626.         if (options & 1) {        /* -s option */
  2627.             dss_s = dss;
  2628.             dss2tv(&dss_s,&tv);
  2629.         }
  2630.         else if (options & 2) {        /* -r option */
  2631.             long diff;
  2632.             struct timeval tv1;
  2633.  
  2634.             /*
  2635.              *  if -s not previous done , silently ignore
  2636.              */
  2637.             if (dss_s.ds_Days == 0)
  2638.                 return 0;
  2639.  
  2640.             dss2tv(&dss, &tv1);        /* current time */
  2641.             diff = tv_diff(&tv,&tv1);    /* diff in msecs */
  2642.  
  2643.             printf ("%d.%02d\n", diff / 1000, diff % 1000);
  2644.         }
  2645.         else
  2646.             printf ("%s %s\n", tday, dates (&dss, 0));
  2647.     }
  2648.     else {
  2649.         /* set the time here  */
  2650.         DateStamp (&dt.dat_Stamp);
  2651.         for (; i < ac; i++) {
  2652.             dt.dat_StrDate = NULL;
  2653.             dt.dat_StrTime = NULL;
  2654.             dt.dat_Flags = DTF_FUTURE;
  2655.             if (index (av[i], ':'))
  2656.                 dt.dat_StrTime = av[i];
  2657.             else
  2658.                 dt.dat_StrDate = av[i];
  2659.             if (!StrToDate (&dt))
  2660.                 ierror (av[i], 500);
  2661.         }
  2662.         setsystemtime (&(dt.dat_Stamp));
  2663.     }
  2664.     return 0;
  2665. }
  2666.  
  2667.